| /* |
| * |
| * Copyright 2019 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 "src/core/lib/service_config/service_config.h" |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "absl/strings/str_cat.h" |
| |
| #include <grpc/grpc.h> |
| |
| #include "src/core/ext/filters/client_channel/resolver_result_parsing.h" |
| #include "src/core/ext/filters/client_channel/retry_service_config.h" |
| #include "src/core/ext/filters/message_size/message_size_filter.h" |
| #include "src/core/lib/gpr/string.h" |
| #include "src/core/lib/gprpp/time.h" |
| #include "src/core/lib/service_config/service_config_impl.h" |
| #include "src/core/lib/service_config/service_config_parser.h" |
| #include "test/core/util/port.h" |
| #include "test/core/util/test_config.h" |
| |
| namespace grpc_core { |
| namespace testing { |
| |
| // |
| // ServiceConfig tests |
| // |
| |
| // Set this channel arg to true to disable parsing. |
| #define GRPC_ARG_DISABLE_PARSING "disable_parsing" |
| |
| // A regular expression to enter referenced or child errors. |
| #ifdef GRPC_ERROR_IS_ABSEIL_STATUS |
| #define CHILD_ERROR_TAG ".*children.*" |
| #else |
| #define CHILD_ERROR_TAG ".*referenced_errors.*" |
| #endif |
| |
| class TestParsedConfig1 : public ServiceConfigParser::ParsedConfig { |
| public: |
| explicit TestParsedConfig1(int value) : value_(value) {} |
| |
| int value() const { return value_; } |
| |
| private: |
| int value_; |
| }; |
| |
| class TestParser1 : public ServiceConfigParser::Parser { |
| public: |
| absl::string_view name() const override { return "test_parser_1"; } |
| |
| std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams( |
| const grpc_channel_args* args, const Json& json, |
| grpc_error_handle* error) override { |
| GPR_DEBUG_ASSERT(error != nullptr); |
| if (grpc_channel_args_find_bool(args, GRPC_ARG_DISABLE_PARSING, false)) { |
| return nullptr; |
| } |
| auto it = json.object_value().find("global_param"); |
| if (it != json.object_value().end()) { |
| if (it->second.type() != Json::Type::NUMBER) { |
| *error = |
| GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidTypeErrorMessage()); |
| return nullptr; |
| } |
| int value = gpr_parse_nonnegative_int(it->second.string_value().c_str()); |
| if (value == -1) { |
| *error = |
| GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage()); |
| return nullptr; |
| } |
| return absl::make_unique<TestParsedConfig1>(value); |
| } |
| return nullptr; |
| } |
| |
| static const char* InvalidTypeErrorMessage() { |
| return "global_param value type should be a number"; |
| } |
| |
| static const char* InvalidValueErrorMessage() { |
| return "global_param value type should be non-negative"; |
| } |
| }; |
| |
| class TestParser2 : public ServiceConfigParser::Parser { |
| public: |
| absl::string_view name() const override { return "test_parser_2"; } |
| |
| std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams( |
| const grpc_channel_args* args, const Json& json, |
| grpc_error_handle* error) override { |
| GPR_DEBUG_ASSERT(error != nullptr); |
| if (grpc_channel_args_find_bool(args, GRPC_ARG_DISABLE_PARSING, false)) { |
| return nullptr; |
| } |
| auto it = json.object_value().find("method_param"); |
| if (it != json.object_value().end()) { |
| if (it->second.type() != Json::Type::NUMBER) { |
| *error = |
| GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidTypeErrorMessage()); |
| return nullptr; |
| } |
| int value = gpr_parse_nonnegative_int(it->second.string_value().c_str()); |
| if (value == -1) { |
| *error = |
| GRPC_ERROR_CREATE_FROM_STATIC_STRING(InvalidValueErrorMessage()); |
| return nullptr; |
| } |
| return absl::make_unique<TestParsedConfig1>(value); |
| } |
| return nullptr; |
| } |
| |
| static const char* InvalidTypeErrorMessage() { |
| return "method_param value type should be a number"; |
| } |
| |
| static const char* InvalidValueErrorMessage() { |
| return "method_param value type should be non-negative"; |
| } |
| }; |
| |
| // This parser always adds errors |
| class ErrorParser : public ServiceConfigParser::Parser { |
| public: |
| explicit ErrorParser(absl::string_view name) : name_(name) {} |
| |
| absl::string_view name() const override { return name_; } |
| |
| std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams( |
| const grpc_channel_args* /*arg*/, const Json& /*json*/, |
| grpc_error_handle* error) override { |
| GPR_DEBUG_ASSERT(error != nullptr); |
| *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(MethodError()); |
| return nullptr; |
| } |
| |
| std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams( |
| const grpc_channel_args* /*arg*/, const Json& /*json*/, |
| grpc_error_handle* error) override { |
| GPR_DEBUG_ASSERT(error != nullptr); |
| *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(GlobalError()); |
| return nullptr; |
| } |
| |
| static const char* MethodError() { return "ErrorParser : methodError"; } |
| |
| static const char* GlobalError() { return "ErrorParser : globalError"; } |
| |
| private: |
| absl::string_view name_; |
| }; |
| |
| class ServiceConfigTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| CoreConfiguration::Reset(); |
| CoreConfiguration::BuildSpecialConfiguration( |
| [](CoreConfiguration::Builder* builder) { |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<TestParser1>()); |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<TestParser2>()); |
| }); |
| EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex( |
| "test_parser_1"), |
| 0); |
| EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex( |
| "test_parser_2"), |
| 1); |
| } |
| }; |
| |
| TEST_F(ServiceConfigTest, ErrorCheck1) { |
| const char* test_json = ""; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex("JSON parse error")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, BasicTest1) { |
| const char* test_json = "{}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_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_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_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_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "multiple method configs with same name")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithNullMethod) { |
| const char* test_json = |
| "{\"methodConfig\": [" |
| " {\"name\":[{\"service\":\"TestServ\",\"method\":null}]}," |
| " {\"name\":[{\"service\":\"TestServ\"}]}" |
| "]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "multiple method configs with same name")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithEmptyMethod) { |
| const char* test_json = |
| "{\"methodConfig\": [" |
| " {\"name\":[{\"service\":\"TestServ\",\"method\":\"\"}]}," |
| " {\"name\":[{\"service\":\"TestServ\"}]}" |
| "]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "multiple method configs with same name")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigs) { |
| const char* test_json = |
| "{\"methodConfig\": [" |
| " {\"name\":[{}]}," |
| " {\"name\":[{}]}" |
| "]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "multiple default method configs")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithNullService) { |
| const char* test_json = |
| "{\"methodConfig\": [" |
| " {\"name\":[{\"service\":null}]}," |
| " {\"name\":[{}]}" |
| "]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "multiple default method configs")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithEmptyService) { |
| const char* test_json = |
| "{\"methodConfig\": [" |
| " {\"name\":[{\"service\":\"\"}]}," |
| " {\"name\":[{}]}" |
| "]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "multiple default method configs")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, ValidMethodConfig) { |
| const char* test_json = |
| "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser1BasicTest1) { |
| const char* test_json = "{\"global_param\":5}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0))) |
| ->value(), |
| 5); |
| EXPECT_EQ(svc_cfg->GetMethodParsedConfigVector( |
| grpc_slice_from_static_string("/TestServ/TestMethod")), |
| nullptr); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser1BasicTest2) { |
| const char* test_json = "{\"global_param\":1000}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0))) |
| ->value(), |
| 1000); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser1DisabledViaChannelArg) { |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_DISABLE_PARSING), 1); |
| grpc_channel_args args = {1, &arg}; |
| const char* test_json = "{\"global_param\":5}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| EXPECT_EQ(svc_cfg->GetGlobalParsedConfig(0), nullptr); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) { |
| const char* test_json = "{\"global_param\":\"5\"}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| absl::StrCat("Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG, |
| TestParser1::InvalidTypeErrorMessage()))); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) { |
| const char* test_json = "{\"global_param\":-5}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| absl::StrCat("Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG, |
| TestParser1::InvalidValueErrorMessage()))); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser2BasicTest) { |
| const char* test_json = |
| "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], " |
| "\"method_param\":5}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_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(), 5); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser2DisabledViaChannelArg) { |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_DISABLE_PARSING), 1); |
| grpc_channel_args args = {1, &arg}; |
| const char* test_json = |
| "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], " |
| "\"method_param\":5}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_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(parsed_config, nullptr); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) { |
| const char* test_json = |
| "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], " |
| "\"method_param\":\"5\"}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex(absl::StrCat( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG, |
| TestParser2::InvalidTypeErrorMessage()))); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) { |
| const char* test_json = |
| "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], " |
| "\"method_param\":-5}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex(absl::StrCat( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG, |
| TestParser2::InvalidValueErrorMessage()))); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST(ServiceConfigParserTest, DoubleRegistration) { |
| CoreConfiguration::Reset(); |
| ASSERT_DEATH_IF_SUPPORTED( |
| CoreConfiguration::BuildSpecialConfiguration( |
| [](CoreConfiguration::Builder* builder) { |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<ErrorParser>("xyzabc")); |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<ErrorParser>("xyzabc")); |
| }), |
| "xyzabc.*already registered"); |
| } |
| |
| // Test parsing with ErrorParsers which always add errors |
| class ErroredParsersScopingTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| CoreConfiguration::Reset(); |
| CoreConfiguration::BuildSpecialConfiguration( |
| [](CoreConfiguration::Builder* builder) { |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<ErrorParser>("ep1")); |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<ErrorParser>("ep2")); |
| }); |
| EXPECT_EQ( |
| CoreConfiguration::Get().service_config_parser().GetParserIndex("ep1"), |
| 0); |
| EXPECT_EQ( |
| CoreConfiguration::Get().service_config_parser().GetParserIndex("ep2"), |
| 1); |
| } |
| }; |
| |
| TEST_F(ErroredParsersScopingTest, GlobalParams) { |
| const char* test_json = "{}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex(absl::StrCat( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG, |
| ErrorParser::GlobalError(), ".*", ErrorParser::GlobalError()))); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ErroredParsersScopingTest, MethodParams) { |
| const char* test_json = "{\"methodConfig\": [{}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex(absl::StrCat( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG, |
| ErrorParser::GlobalError(), ".*", ErrorParser::GlobalError(), |
| ".*Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG, |
| ErrorParser::MethodError(), ".*", ErrorParser::MethodError()))); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| // |
| // client_channel parser tests |
| // |
| |
| class ClientChannelParserTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| CoreConfiguration::Reset(); |
| CoreConfiguration::BuildSpecialConfiguration( |
| [](CoreConfiguration::Builder* builder) { |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<internal::ClientChannelServiceConfigParser>()); |
| }); |
| EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex( |
| "client_channel"), |
| 0); |
| } |
| }; |
| |
| TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) { |
| const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = |
| static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| auto lb_config = parsed_config->parsed_lb_config(); |
| EXPECT_STREQ(lb_config->name(), "pick_first"); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) { |
| const char* test_json = |
| "{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| auto parsed_config = static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| auto lb_config = parsed_config->parsed_lb_config(); |
| EXPECT_STREQ(lb_config->name(), "round_robin"); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) { |
| const char* test_json = |
| "{\"loadBalancingConfig\": " |
| "[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = |
| static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| auto lb_config = parsed_config->parsed_lb_config(); |
| EXPECT_STREQ(lb_config->name(), "grpclb"); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) { |
| const char* test_json = |
| "{\n" |
| " \"loadBalancingConfig\":[\n" |
| " { \"does_not_exist\":{} },\n" |
| " { \"xds_cluster_resolver_experimental\":{\n" |
| " \"discoveryMechanisms\": [\n" |
| " { \"clusterName\": \"foo\",\n" |
| " \"type\": \"EDS\"\n" |
| " } ]\n" |
| " } }\n" |
| " ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = |
| static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| auto lb_config = parsed_config->parsed_lb_config(); |
| EXPECT_STREQ(lb_config->name(), "xds_cluster_resolver_experimental"); |
| } |
| |
| TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) { |
| const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex("Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG |
| "Client channel global parser" CHILD_ERROR_TAG |
| "field:loadBalancingConfig" CHILD_ERROR_TAG |
| "No known policies in list: unknown")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) { |
| const char* test_json = |
| "{\"loadBalancingConfig\": [" |
| " {\"grpclb\":{\"childPolicy\":1}}," |
| " {\"round_robin\":{}}" |
| "]}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG |
| "Client channel global parser" CHILD_ERROR_TAG |
| "field:loadBalancingConfig" CHILD_ERROR_TAG |
| "GrpcLb Parser" CHILD_ERROR_TAG |
| "field:childPolicy" CHILD_ERROR_TAG "type should be array")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) { |
| const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = |
| static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first"); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) { |
| const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = |
| static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first"); |
| } |
| |
| TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) { |
| const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG |
| "Client channel global parser" CHILD_ERROR_TAG |
| "field:loadBalancingPolicy error:Unknown lb policy")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) { |
| const char* test_json = |
| "{\"loadBalancingPolicy\":\"xds_cluster_resolver_experimental\"}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG |
| "Client channel global parser" CHILD_ERROR_TAG |
| "field:loadBalancingPolicy " |
| "error:xds_cluster_resolver_experimental requires " |
| "a config. Please use loadBalancingConfig instead.")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidTimeout) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"timeout\": \"5s\"\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_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)[0]).get(); |
| EXPECT_EQ( |
| (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config)) |
| ->timeout(), |
| Duration::Seconds(5)); |
| } |
| |
| TEST_F(ClientChannelParserTest, InvalidTimeout) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"service\", \"method\": \"method\" }\n" |
| " ],\n" |
| " \"timeout\": \"5sec\"\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "Client channel parser" CHILD_ERROR_TAG |
| "field:timeout error:type should be STRING of the form given " |
| "by google.proto.Duration")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidWaitForReady) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"waitForReady\": true\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_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)[0]).get(); |
| ASSERT_TRUE( |
| (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config)) |
| ->wait_for_ready() |
| .has_value()); |
| EXPECT_TRUE( |
| (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config)) |
| ->wait_for_ready() |
| .value()); |
| } |
| |
| TEST_F(ClientChannelParserTest, InvalidWaitForReady) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"service\", \"method\": \"method\" }\n" |
| " ],\n" |
| " \"waitForReady\": \"true\"\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "Client channel parser" CHILD_ERROR_TAG |
| "field:waitForReady error:Type should be true/false")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(ClientChannelParserTest, ValidHealthCheck) { |
| const char* test_json = |
| "{\n" |
| " \"healthCheckConfig\": {\n" |
| " \"serviceName\": \"health_check_service_name\"\n" |
| " }\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = |
| static_cast<internal::ClientChannelGlobalParsedConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->health_check_service_name(), |
| "health_check_service_name"); |
| } |
| |
| TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) { |
| const char* test_json = |
| "{\n" |
| " \"healthCheckConfig\": {\n" |
| " \"serviceName\": \"health_check_service_name\"\n" |
| " },\n" |
| " \"healthCheckConfig\": {\n" |
| " \"serviceName\": \"health_check_service_name1\"\n" |
| " }\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "JSON parsing failed" CHILD_ERROR_TAG |
| "duplicate key \"healthCheckConfig\" at index 104")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| // |
| // retry parser tests |
| // |
| |
| class RetryParserTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| CoreConfiguration::Reset(); |
| CoreConfiguration::BuildSpecialConfiguration( |
| [](CoreConfiguration::Builder* builder) { |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<internal::RetryServiceConfigParser>()); |
| }); |
| EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex( |
| "retry"), |
| 0); |
| } |
| }; |
| |
| TEST_F(RetryParserTest, ValidRetryThrottling) { |
| const char* test_json = |
| "{\n" |
| " \"retryThrottling\": {\n" |
| " \"maxTokens\": 2,\n" |
| " \"tokenRatio\": 1.0\n" |
| " }\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* parsed_config = static_cast<internal::RetryGlobalConfig*>( |
| svc_cfg->GetGlobalParsedConfig(0)); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->max_milli_tokens(), 2000); |
| EXPECT_EQ(parsed_config->milli_token_ratio(), 1000); |
| } |
| |
| TEST_F(RetryParserTest, RetryThrottlingMissingFields) { |
| const char* test_json = |
| "{\n" |
| " \"retryThrottling\": {\n" |
| " }\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG "retryThrottling" CHILD_ERROR_TAG |
| "field:retryThrottling field:maxTokens error:Not found" |
| ".*field:retryThrottling field:tokenRatio error:Not found")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryThrottlingNegativeMaxTokens) { |
| const char* test_json = |
| "{\n" |
| " \"retryThrottling\": {\n" |
| " \"maxTokens\": -2,\n" |
| " \"tokenRatio\": 1.0\n" |
| " }\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG "retryThrottling" CHILD_ERROR_TAG |
| "field:retryThrottling field:maxTokens error:should " |
| "be greater than zero")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryThrottlingInvalidTokenRatio) { |
| const char* test_json = |
| "{\n" |
| " \"retryThrottling\": {\n" |
| " \"maxTokens\": 2,\n" |
| " \"tokenRatio\": -1\n" |
| " }\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT( |
| grpc_error_std_string(error), |
| ::testing::ContainsRegex("Service config parsing error" CHILD_ERROR_TAG |
| "Global Params" CHILD_ERROR_TAG |
| "retryThrottling" CHILD_ERROR_TAG |
| "field:retryThrottling field:tokenRatio " |
| "error:Failed parsing")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, ValidRetryPolicy) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 3,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( |
| grpc_slice_from_static_string("/TestServ/TestMethod")); |
| ASSERT_NE(vector_ptr, nullptr); |
| const auto* parsed_config = |
| static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get()); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->max_attempts(), 3); |
| EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1)); |
| EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2)); |
| EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f); |
| EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), absl::nullopt); |
| EXPECT_TRUE( |
| parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED)); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": 5\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "field:retryPolicy error:should be of type object")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyRequiredFieldsMissing) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| ".*field:maxAttempts error:required field missing" |
| ".*field:initialBackoff error:does not exist" |
| ".*field:maxBackoff error:does not exist" |
| ".*field:backoffMultiplier error:required field missing")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyMaxAttemptsWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": \"FOO\",\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:maxAttempts error:should be of type number")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyMaxAttemptsBadValue) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 1,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:maxAttempts error:should be at least 2")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyInitialBackoffWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1sec\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:initialBackoff error:type should be STRING of the " |
| "form given by google.proto.Duration")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyInitialBackoffBadValue) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"0s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:initialBackoff error:must be greater than 0")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyMaxBackoffWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120sec\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:maxBackoff error:type should be STRING of the form " |
| "given by google.proto.Duration")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyMaxBackoffBadValue) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"0s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:maxBackoff error:must be greater than 0")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyBackoffMultiplierWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:backoffMultiplier error:should be of type number")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyBackoffMultiplierBadValue) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 0,\n" |
| " \"retryableStatusCodes\": [ \"ABORTED\" ]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:backoffMultiplier error:must be greater than 0")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyEmptyRetryableStatusCodes) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"retryableStatusCodes\": []\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:retryableStatusCodes error:must be non-empty")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyRetryableStatusCodesWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"retryableStatusCodes\": 0\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:retryableStatusCodes error:must be of type array")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyUnparseableRetryableStatusCodes) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"retryableStatusCodes\": [\"FOO\", 2]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG "field:retryableStatusCodes " |
| "error:failed to parse status code" |
| ".*field:retryableStatusCodes " |
| "error:status codes should be of type string")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, ValidRetryPolicyWithPerAttemptRecvTimeout) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"perAttemptRecvTimeout\": \"1s\",\n" |
| " \"retryableStatusCodes\": [\"ABORTED\"]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1); |
| grpc_channel_args args = {1, &arg}; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( |
| grpc_slice_from_static_string("/TestServ/TestMethod")); |
| ASSERT_NE(vector_ptr, nullptr); |
| const auto* parsed_config = |
| static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get()); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->max_attempts(), 2); |
| EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1)); |
| EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2)); |
| EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f); |
| EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), Duration::Seconds(1)); |
| EXPECT_TRUE( |
| parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED)); |
| } |
| |
| TEST_F(RetryParserTest, |
| ValidRetryPolicyWithPerAttemptRecvTimeoutIgnoredWhenHedgingDisabled) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"perAttemptRecvTimeout\": \"1s\",\n" |
| " \"retryableStatusCodes\": [\"ABORTED\"]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( |
| grpc_slice_from_static_string("/TestServ/TestMethod")); |
| ASSERT_NE(vector_ptr, nullptr); |
| const auto* parsed_config = |
| static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get()); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->max_attempts(), 2); |
| EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1)); |
| EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2)); |
| EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f); |
| EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), absl::nullopt); |
| EXPECT_TRUE( |
| parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED)); |
| } |
| |
| TEST_F(RetryParserTest, |
| ValidRetryPolicyWithPerAttemptRecvTimeoutAndUnsetRetryableStatusCodes) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": 1.6,\n" |
| " \"perAttemptRecvTimeout\": \"1s\"\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1); |
| grpc_channel_args args = {1, &arg}; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( |
| grpc_slice_from_static_string("/TestServ/TestMethod")); |
| ASSERT_NE(vector_ptr, nullptr); |
| const auto* parsed_config = |
| static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get()); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->max_attempts(), 2); |
| EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1)); |
| EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2)); |
| EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f); |
| EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), Duration::Seconds(1)); |
| EXPECT_TRUE(parsed_config->retryable_status_codes().Empty()); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyPerAttemptRecvTimeoutUnparseable) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"perAttemptRecvTimeout\": \"1sec\",\n" |
| " \"retryableStatusCodes\": [\"ABORTED\"]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1); |
| grpc_channel_args args = {1, &arg}; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:perAttemptRecvTimeout error:type must be STRING " |
| "of the form given by google.proto.Duration.")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyPerAttemptRecvTimeoutWrongType) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"perAttemptRecvTimeout\": 1,\n" |
| " \"retryableStatusCodes\": [\"ABORTED\"]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1); |
| grpc_channel_args args = {1, &arg}; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:perAttemptRecvTimeout error:type must be STRING " |
| "of the form given by google.proto.Duration.")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(RetryParserTest, InvalidRetryPolicyPerAttemptRecvTimeoutBadValue) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"retryPolicy\": {\n" |
| " \"maxAttempts\": 2,\n" |
| " \"initialBackoff\": \"1s\",\n" |
| " \"maxBackoff\": \"120s\",\n" |
| " \"backoffMultiplier\": \"1.6\",\n" |
| " \"perAttemptRecvTimeout\": \"0s\",\n" |
| " \"retryableStatusCodes\": [\"ABORTED\"]\n" |
| " }\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| grpc_arg arg = grpc_channel_arg_integer_create( |
| const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1); |
| grpc_channel_args args = {1, &arg}; |
| auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "retryPolicy" CHILD_ERROR_TAG |
| "field:perAttemptRecvTimeout error:must be greater than 0")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| // |
| // message_size parser tests |
| // |
| |
| class MessageSizeParserTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| CoreConfiguration::Reset(); |
| CoreConfiguration::BuildSpecialConfiguration( |
| [](CoreConfiguration::Builder* builder) { |
| builder->service_config_parser()->RegisterParser( |
| absl::make_unique<MessageSizeParser>()); |
| }); |
| EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex( |
| "message_size"), |
| 0); |
| } |
| }; |
| |
| TEST_F(MessageSizeParserTest, Valid) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"maxRequestMessageBytes\": 1024,\n" |
| " \"maxResponseMessageBytes\": 1024\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error); |
| const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector( |
| grpc_slice_from_static_string("/TestServ/TestMethod")); |
| ASSERT_NE(vector_ptr, nullptr); |
| auto parsed_config = |
| static_cast<MessageSizeParsedConfig*>(((*vector_ptr)[0]).get()); |
| ASSERT_NE(parsed_config, nullptr); |
| EXPECT_EQ(parsed_config->limits().max_send_size, 1024); |
| EXPECT_EQ(parsed_config->limits().max_recv_size, 1024); |
| } |
| |
| TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"maxRequestMessageBytes\": -1024\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "Message size parser" CHILD_ERROR_TAG |
| "field:maxRequestMessageBytes error:should be non-negative")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) { |
| const char* test_json = |
| "{\n" |
| " \"methodConfig\": [ {\n" |
| " \"name\": [\n" |
| " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n" |
| " ],\n" |
| " \"maxResponseMessageBytes\": {}\n" |
| " } ]\n" |
| "}"; |
| grpc_error_handle error = GRPC_ERROR_NONE; |
| auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error); |
| EXPECT_THAT(grpc_error_std_string(error), |
| ::testing::ContainsRegex( |
| "Service config parsing error" CHILD_ERROR_TAG |
| "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG |
| "Message size parser" CHILD_ERROR_TAG |
| "field:maxResponseMessageBytes error:should be of type " |
| "number")); |
| GRPC_ERROR_UNREF(error); |
| } |
| |
| } // namespace testing |
| } // namespace grpc_core |
| |
| int main(int argc, char** argv) { |
| ::testing::InitGoogleTest(&argc, argv); |
| grpc::testing::TestEnvironment env(argc, argv); |
| grpc_init(); |
| int ret = RUN_ALL_TESTS(); |
| grpc_shutdown(); |
| return ret; |
| } |