service config: use new JSON API (#30467)

* Declarative JSON parser

* Automated change: Fix sanity tests

* fix

* shrinking stuff a little

* static vtables

* separate fns

* simpler?

* make maps work

* windows fixes

* Automated change: Fix sanity tests

* simplify code

* Automated change: Fix sanity tests

* vtable-test

* dont always create vec/map impls for every type

* comments

* make error consistent

* move method private

* progress

* durations!

* Automated change: Fix sanity tests

* fix

* fix

* fix

* Automated change: Fix sanity tests

* post-load

* Automated change: Fix sanity tests

* document JsonPostLoad() and add static_assert

* don't copy field names, to avoid length limitations

* use absl::Status

* accept either string or number for numeric values

* add test for direct data member of another struct type

* remove unused method

* add support for retaining part of the JSON wirthout processing

* update test for changes in Json::Parse() API

* add absl::optional support

* Automated change: Fix sanity tests

* fix tests, improve error messages, and add overload to parse to existing object

* remove overload of LoadFromJson()

* change special case for Json to instead use Json::Object

* rename resolver_result_parsing to client_channel_service_config

* split up service_config_test into a separate test for each component

* convert client channel service config parser to new API

* fix build

* converted retry global params

* convert retry method-level parsing, but still need to find a way to control parsing via a channel arg

* improve error structure, add missing types, and improve tests

* clang-format

* Automated change: Fix sanity tests

* fix build

* add LoadJsonObjectField(), add LoadFromJson() overload that takes an ErrorList parameter, and add tests for parsing bare top-level types

* fix msan

* Automated change: Fix sanity tests

* fix error message

* Automated change: Fix sanity tests

* fix test

* add ability to disable fields

* plumb in channel args to disable parsing

* Automated change: Fix sanity tests

* use const char* instead of absl::string_view for enable_key

* fix resolver_component_test

* Automated change: Fix sanity tests

* work around mac build problem

* Automated change: Fix sanity tests

* work around gcc6 problem

* Automated change: Fix sanity tests

* fix build

* fix build

* don't use alternative builder in tests

* convert message size service config parser

* convert fault injection service config parser

* rename files

* add specialization for unique_ptr

* avoid moves in client channel service config parser

* avoid moves in retry service config parser, and do some cleanup

* avoid moves in message_size service config parser

* avoid moves for fault injection service config parser, and use internal channel arg

* convert rbac service config parser

* clang-format

* WIP

* convert top-level service config parser

* clang-format

* fix build

* fix rbac service config parser test

* fix signed-ness problem and reversed-conditional bug

* fix unused param

* fix json_string method

* fix max message length defaults

* add copy ctors to appease windows compiler

* fix RLS LB config parser test

* fix name resolution test

* fix build

* work around gmock portability bug

* fix sanity

* add missing build dep

* make RBAC principal and permissions movable, not copyable

* Revert "make RBAC principal and permissions movable, not copyable"

This reverts commit 53315bccc9.

* attempt to simplify HeaderMatcher and StringMatcher parsing

* more bloat reduction in RBAC service config parser

* fix sanity

* add missing build dep

* attempt work-around for MSVC bug

* Revert "attempt work-around for MSVC bug"

This reverts commit e54c89e1e4.

* attempt work-around for Windows build problem

* try another work-around

* fix sanity

* appease clang-tidy

* generate_projects

* attempt to fix Windows build

* more windows fixes

* more windows fix

* yet more windows fixes

* try without noexcept

* remove unnecessary boilerplate

* code review changes

* fix breakage

Co-authored-by: Craig Tiller <craig.tiller@gmail.com>
Co-authored-by: ctiller <ctiller@users.noreply.github.com>
Co-authored-by: Craig Tiller <ctiller@google.com>
Co-authored-by: markdroth <markdroth@users.noreply.github.com>
revert-31481-reland-try
Mark D. Roth 2 years ago committed by GitHub
parent f29f861ed3
commit b853ccc6db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      BUILD
  2. 119
      CMakeLists.txt
  3. 10
      Makefile
  4. 49
      build_autogenerated.yaml
  5. 4
      config.m4
  6. 4
      config.w32
  7. 10
      gRPC-C++.podspec
  8. 14
      gRPC-Core.podspec
  9. 9
      grpc.gemspec
  10. 9
      grpc.gyp
  11. 9
      package.xml
  12. 25
      src/core/BUILD
  13. 2
      src/core/ext/filters/client_channel/client_channel.cc
  14. 2
      src/core/ext/filters/client_channel/client_channel_plugin.cc
  15. 153
      src/core/ext/filters/client_channel/client_channel_service_config.cc
  16. 49
      src/core/ext/filters/client_channel/client_channel_service_config.h
  17. 9
      src/core/ext/filters/client_channel/lb_policy/rls/rls.cc
  18. 186
      src/core/ext/filters/client_channel/resolver_result_parsing.cc
  19. 393
      src/core/ext/filters/client_channel/retry_service_config.cc
  20. 43
      src/core/ext/filters/client_channel/retry_service_config.h
  21. 16
      src/core/ext/filters/client_channel/retry_throttle.cc
  22. 15
      src/core/ext/filters/client_channel/retry_throttle.h
  23. 2
      src/core/ext/filters/fault_injection/fault_injection_filter.cc
  24. 118
      src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
  25. 28
      src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h
  26. 185
      src/core/ext/filters/fault_injection/service_config_parser.cc
  27. 22
      src/core/ext/filters/http/message_compress/message_decompress_filter.cc
  28. 168
      src/core/ext/filters/message_size/message_size_filter.cc
  29. 37
      src/core/ext/filters/message_size/message_size_filter.h
  30. 1208
      src/core/ext/filters/rbac/rbac_service_config_parser.cc
  31. 7
      src/core/ext/filters/rbac/rbac_service_config_parser.h
  32. 2
      src/core/ext/xds/xds_http_fault_filter.cc
  33. 6
      src/core/ext/xds/xds_http_rbac_filter.cc
  34. 21
      src/core/lib/json/json_object_loader.h
  35. 2
      src/core/lib/service_config/service_config.h
  36. 250
      src/core/lib/service_config/service_config_impl.cc
  37. 31
      src/core/lib/service_config/service_config_impl.h
  38. 45
      src/core/lib/service_config/service_config_parser.cc
  39. 24
      src/core/lib/service_config/service_config_parser.h
  40. 4
      src/python/grpcio/grpc_core_dependencies.py
  41. 18
      test/core/client_channel/BUILD
  42. 315
      test/core/client_channel/client_channel_service_config_test.cc
  43. 712
      test/core/client_channel/retry_service_config_test.cc
  44. 34
      test/core/client_channel/rls_lb_config_parser_test.cc
  45. 1557
      test/core/client_channel/service_config_test.cc
  46. 240
      test/core/ext/filters/rbac/rbac_service_config_parser_test.cc
  47. 124
      test/core/json/json_object_loader_test.cc
  48. 33
      test/core/message_size/BUILD
  49. 125
      test/core/message_size/message_size_service_config_test.cc
  50. 33
      test/core/service_config/BUILD
  51. 468
      test/core/service_config/service_config_test.cc
  52. 4
      test/core/xds/xds_http_filters_test.cc
  53. 4
      test/cpp/naming/resolver_component_tests_runner.py
  54. 4
      test/cpp/naming/resolver_test_record_groups.yaml
  55. 9
      tools/doxygen/Doxyfile.c++.internal
  56. 9
      tools/doxygen/Doxyfile.core.internal
  57. 72
      tools/run_tests/generated/tests.json

14
BUILD

@ -2503,9 +2503,9 @@ grpc_cc_library(
"//src/core:lib/service_config/service_config_impl.h", "//src/core:lib/service_config/service_config_impl.h",
], ],
external_deps = [ external_deps = [
"absl/status",
"absl/status:statusor", "absl/status:statusor",
"absl/strings", "absl/strings",
"absl/types:optional",
], ],
language = "c++", language = "c++",
visibility = ["@grpc:client_channel"], visibility = ["@grpc:client_channel"],
@ -2516,9 +2516,12 @@ grpc_cc_library(
"//src/core:channel_args", "//src/core:channel_args",
"//src/core:grpc_service_config", "//src/core:grpc_service_config",
"//src/core:json", "//src/core:json",
"//src/core:json_args",
"//src/core:json_object_loader",
"//src/core:service_config_parser", "//src/core:service_config_parser",
"//src/core:slice", "//src/core:slice",
"//src/core:slice_refcount", "//src/core:slice_refcount",
"//src/core:validation_errors",
], ],
) )
@ -2589,6 +2592,7 @@ grpc_cc_library(
"//src/core:ext/filters/client_channel/client_channel_channelz.cc", "//src/core:ext/filters/client_channel/client_channel_channelz.cc",
"//src/core:ext/filters/client_channel/client_channel_factory.cc", "//src/core:ext/filters/client_channel/client_channel_factory.cc",
"//src/core:ext/filters/client_channel/client_channel_plugin.cc", "//src/core:ext/filters/client_channel/client_channel_plugin.cc",
"//src/core:ext/filters/client_channel/client_channel_service_config.cc",
"//src/core:ext/filters/client_channel/config_selector.cc", "//src/core:ext/filters/client_channel/config_selector.cc",
"//src/core:ext/filters/client_channel/dynamic_filters.cc", "//src/core:ext/filters/client_channel/dynamic_filters.cc",
"//src/core:ext/filters/client_channel/global_subchannel_pool.cc", "//src/core:ext/filters/client_channel/global_subchannel_pool.cc",
@ -2597,7 +2601,6 @@ grpc_cc_library(
"//src/core:ext/filters/client_channel/lb_policy/child_policy_handler.cc", "//src/core:ext/filters/client_channel/lb_policy/child_policy_handler.cc",
"//src/core:ext/filters/client_channel/lb_policy/oob_backend_metric.cc", "//src/core:ext/filters/client_channel/lb_policy/oob_backend_metric.cc",
"//src/core:ext/filters/client_channel/local_subchannel_pool.cc", "//src/core:ext/filters/client_channel/local_subchannel_pool.cc",
"//src/core:ext/filters/client_channel/resolver_result_parsing.cc",
"//src/core:ext/filters/client_channel/retry_filter.cc", "//src/core:ext/filters/client_channel/retry_filter.cc",
"//src/core:ext/filters/client_channel/retry_service_config.cc", "//src/core:ext/filters/client_channel/retry_service_config.cc",
"//src/core:ext/filters/client_channel/retry_throttle.cc", "//src/core:ext/filters/client_channel/retry_throttle.cc",
@ -2612,6 +2615,7 @@ grpc_cc_library(
"//src/core:ext/filters/client_channel/client_channel.h", "//src/core:ext/filters/client_channel/client_channel.h",
"//src/core:ext/filters/client_channel/client_channel_channelz.h", "//src/core:ext/filters/client_channel/client_channel_channelz.h",
"//src/core:ext/filters/client_channel/client_channel_factory.h", "//src/core:ext/filters/client_channel/client_channel_factory.h",
"//src/core:ext/filters/client_channel/client_channel_service_config.h",
"//src/core:ext/filters/client_channel/config_selector.h", "//src/core:ext/filters/client_channel/config_selector.h",
"//src/core:ext/filters/client_channel/connector.h", "//src/core:ext/filters/client_channel/connector.h",
"//src/core:ext/filters/client_channel/dynamic_filters.h", "//src/core:ext/filters/client_channel/dynamic_filters.h",
@ -2621,7 +2625,6 @@ grpc_cc_library(
"//src/core:ext/filters/client_channel/lb_policy/child_policy_handler.h", "//src/core:ext/filters/client_channel/lb_policy/child_policy_handler.h",
"//src/core:ext/filters/client_channel/lb_policy/oob_backend_metric.h", "//src/core:ext/filters/client_channel/lb_policy/oob_backend_metric.h",
"//src/core:ext/filters/client_channel/local_subchannel_pool.h", "//src/core:ext/filters/client_channel/local_subchannel_pool.h",
"//src/core:ext/filters/client_channel/resolver_result_parsing.h",
"//src/core:ext/filters/client_channel/retry_filter.h", "//src/core:ext/filters/client_channel/retry_filter.h",
"//src/core:ext/filters/client_channel/retry_service_config.h", "//src/core:ext/filters/client_channel/retry_service_config.h",
"//src/core:ext/filters/client_channel/retry_throttle.h", "//src/core:ext/filters/client_channel/retry_throttle.h",
@ -2680,7 +2683,9 @@ grpc_cc_library(
"//src/core:init_internally", "//src/core:init_internally",
"//src/core:iomgr_fwd", "//src/core:iomgr_fwd",
"//src/core:json", "//src/core:json",
"//src/core:json_util", "//src/core:json_args",
"//src/core:json_channel_args",
"//src/core:json_object_loader",
"//src/core:lb_policy", "//src/core:lb_policy",
"//src/core:lb_policy_registry", "//src/core:lb_policy_registry",
"//src/core:memory_quota", "//src/core:memory_quota",
@ -2701,6 +2706,7 @@ grpc_cc_library(
"//src/core:transport_fwd", "//src/core:transport_fwd",
"//src/core:unique_type_name", "//src/core:unique_type_name",
"//src/core:useful", "//src/core:useful",
"//src/core:validation_errors",
], ],
) )

119
CMakeLists.txt generated

@ -870,6 +870,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx client_auth_filter_test) add_dependencies(buildtests_cxx client_auth_filter_test)
add_dependencies(buildtests_cxx client_authority_filter_test) add_dependencies(buildtests_cxx client_authority_filter_test)
add_dependencies(buildtests_cxx client_callback_end2end_test) add_dependencies(buildtests_cxx client_callback_end2end_test)
add_dependencies(buildtests_cxx client_channel_service_config_test)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
add_dependencies(buildtests_cxx client_channel_stress_test) add_dependencies(buildtests_cxx client_channel_stress_test)
endif() endif()
@ -1033,6 +1034,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx memory_quota_test) add_dependencies(buildtests_cxx memory_quota_test)
add_dependencies(buildtests_cxx message_allocator_end2end_test) add_dependencies(buildtests_cxx message_allocator_end2end_test)
add_dependencies(buildtests_cxx message_compress_test) add_dependencies(buildtests_cxx message_compress_test)
add_dependencies(buildtests_cxx message_size_service_config_test)
add_dependencies(buildtests_cxx metadata_map_test) add_dependencies(buildtests_cxx metadata_map_test)
add_dependencies(buildtests_cxx miscompile_with_no_unique_address_test) add_dependencies(buildtests_cxx miscompile_with_no_unique_address_test)
add_dependencies(buildtests_cxx mock_stream_test) add_dependencies(buildtests_cxx mock_stream_test)
@ -1098,6 +1100,7 @@ if(gRPC_BUILD_TESTS)
endif() endif()
add_dependencies(buildtests_cxx resolve_address_using_native_resolver_test) add_dependencies(buildtests_cxx resolve_address_using_native_resolver_test)
add_dependencies(buildtests_cxx resource_quota_test) add_dependencies(buildtests_cxx resource_quota_test)
add_dependencies(buildtests_cxx retry_service_config_test)
add_dependencies(buildtests_cxx retry_throttle_test) add_dependencies(buildtests_cxx retry_throttle_test)
add_dependencies(buildtests_cxx rls_end2end_test) add_dependencies(buildtests_cxx rls_end2end_test)
add_dependencies(buildtests_cxx rls_lb_config_parser_test) add_dependencies(buildtests_cxx rls_lb_config_parser_test)
@ -1655,6 +1658,7 @@ add_library(grpc
src/core/ext/filters/client_channel/client_channel_channelz.cc src/core/ext/filters/client_channel/client_channel_channelz.cc
src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/client_channel_service_config.cc
src/core/ext/filters/client_channel/config_selector.cc src/core/ext/filters/client_channel/config_selector.cc
src/core/ext/filters/client_channel/dynamic_filters.cc src/core/ext/filters/client_channel/dynamic_filters.cc
src/core/ext/filters/client_channel/global_subchannel_pool.cc src/core/ext/filters/client_channel/global_subchannel_pool.cc
@ -1696,7 +1700,6 @@ add_library(grpc
src/core/ext/filters/client_channel/resolver/polling_resolver.cc src/core/ext/filters/client_channel/resolver/polling_resolver.cc
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_filter.cc src/core/ext/filters/client_channel/retry_filter.cc
src/core/ext/filters/client_channel/retry_service_config.cc src/core/ext/filters/client_channel/retry_service_config.cc
src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/retry_throttle.cc
@ -1706,7 +1709,7 @@ add_library(grpc
src/core/ext/filters/client_channel/subchannel_stream_client.cc src/core/ext/filters/client_channel/subchannel_stream_client.cc
src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/fault_injection/fault_injection_filter.cc src/core/ext/filters/fault_injection/fault_injection_filter.cc
src/core/ext/filters/fault_injection/service_config_parser.cc src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
src/core/ext/filters/http/client/http_client_filter.cc src/core/ext/filters/http/client/http_client_filter.cc
src/core/ext/filters/http/client_authority_filter.cc src/core/ext/filters/http/client_authority_filter.cc
src/core/ext/filters/http/http_filters_plugin.cc src/core/ext/filters/http/http_filters_plugin.cc
@ -2608,6 +2611,7 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/client_channel_channelz.cc src/core/ext/filters/client_channel/client_channel_channelz.cc
src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_factory.cc
src/core/ext/filters/client_channel/client_channel_plugin.cc src/core/ext/filters/client_channel/client_channel_plugin.cc
src/core/ext/filters/client_channel/client_channel_service_config.cc
src/core/ext/filters/client_channel/config_selector.cc src/core/ext/filters/client_channel/config_selector.cc
src/core/ext/filters/client_channel/dynamic_filters.cc src/core/ext/filters/client_channel/dynamic_filters.cc
src/core/ext/filters/client_channel/global_subchannel_pool.cc src/core/ext/filters/client_channel/global_subchannel_pool.cc
@ -2641,7 +2645,6 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
src/core/ext/filters/client_channel/resolver/polling_resolver.cc src/core/ext/filters/client_channel/resolver/polling_resolver.cc
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
src/core/ext/filters/client_channel/resolver_result_parsing.cc
src/core/ext/filters/client_channel/retry_filter.cc src/core/ext/filters/client_channel/retry_filter.cc
src/core/ext/filters/client_channel/retry_service_config.cc src/core/ext/filters/client_channel/retry_service_config.cc
src/core/ext/filters/client_channel/retry_throttle.cc src/core/ext/filters/client_channel/retry_throttle.cc
@ -2651,7 +2654,7 @@ add_library(grpc_unsecure
src/core/ext/filters/client_channel/subchannel_stream_client.cc src/core/ext/filters/client_channel/subchannel_stream_client.cc
src/core/ext/filters/deadline/deadline_filter.cc src/core/ext/filters/deadline/deadline_filter.cc
src/core/ext/filters/fault_injection/fault_injection_filter.cc src/core/ext/filters/fault_injection/fault_injection_filter.cc
src/core/ext/filters/fault_injection/service_config_parser.cc src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
src/core/ext/filters/http/client/http_client_filter.cc src/core/ext/filters/http/client/http_client_filter.cc
src/core/ext/filters/http/client_authority_filter.cc src/core/ext/filters/http/client_authority_filter.cc
src/core/ext/filters/http/http_filters_plugin.cc src/core/ext/filters/http/http_filters_plugin.cc
@ -2840,7 +2843,6 @@ add_library(grpc_unsecure
src/core/lib/iomgr/wakeup_fd_posix.cc src/core/lib/iomgr/wakeup_fd_posix.cc
src/core/lib/json/json_object_loader.cc src/core/lib/json/json_object_loader.cc
src/core/lib/json/json_reader.cc src/core/lib/json/json_reader.cc
src/core/lib/json/json_util.cc
src/core/lib/json/json_writer.cc src/core/lib/json/json_writer.cc
src/core/lib/load_balancing/lb_policy.cc src/core/lib/load_balancing/lb_policy.cc
src/core/lib/load_balancing/lb_policy_registry.cc src/core/lib/load_balancing/lb_policy_registry.cc
@ -7839,6 +7841,41 @@ target_link_libraries(client_callback_end2end_test
) )
endif()
if(gRPC_BUILD_TESTS)
add_executable(client_channel_service_config_test
test/core/client_channel/client_channel_service_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(client_channel_service_config_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(client_channel_service_config_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX) if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -13621,6 +13658,41 @@ target_link_libraries(message_compress_test
) )
endif()
if(gRPC_BUILD_TESTS)
add_executable(message_size_service_config_test
test/core/message_size/message_size_service_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(message_size_service_config_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(message_size_service_config_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
@ -15744,6 +15816,41 @@ target_link_libraries(resource_quota_test
) )
endif()
if(gRPC_BUILD_TESTS)
add_executable(retry_service_config_test
test/core/client_channel/retry_service_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc
)
target_include_directories(retry_service_config_test
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/include
${_gRPC_ADDRESS_SORTING_INCLUDE_DIR}
${_gRPC_RE2_INCLUDE_DIR}
${_gRPC_SSL_INCLUDE_DIR}
${_gRPC_UPB_GENERATED_DIR}
${_gRPC_UPB_GRPC_GENERATED_DIR}
${_gRPC_UPB_INCLUDE_DIR}
${_gRPC_XXHASH_INCLUDE_DIR}
${_gRPC_ZLIB_INCLUDE_DIR}
third_party/googletest/googletest/include
third_party/googletest/googletest
third_party/googletest/googlemock/include
third_party/googletest/googlemock
${_gRPC_PROTO_GENS_DIR}
)
target_link_libraries(retry_service_config_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
grpc_test_util
)
endif() endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
@ -16748,7 +16855,7 @@ endif()
if(gRPC_BUILD_TESTS) if(gRPC_BUILD_TESTS)
add_executable(service_config_test add_executable(service_config_test
test/core/client_channel/service_config_test.cc test/core/service_config/service_config_test.cc
third_party/googletest/googletest/src/gtest-all.cc third_party/googletest/googletest/src/gtest-all.cc
third_party/googletest/googlemock/src/gmock-all.cc third_party/googletest/googlemock/src/gmock-all.cc
) )

10
Makefile generated

@ -968,6 +968,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/client_channel_channelz.cc \ src/core/ext/filters/client_channel/client_channel_channelz.cc \
src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/client_channel_service_config.cc \
src/core/ext/filters/client_channel/config_selector.cc \ src/core/ext/filters/client_channel/config_selector.cc \
src/core/ext/filters/client_channel/dynamic_filters.cc \ src/core/ext/filters/client_channel/dynamic_filters.cc \
src/core/ext/filters/client_channel/global_subchannel_pool.cc \ src/core/ext/filters/client_channel/global_subchannel_pool.cc \
@ -1009,7 +1010,6 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \
@ -1019,7 +1019,7 @@ LIBGRPC_SRC = \
src/core/ext/filters/client_channel/subchannel_stream_client.cc \ src/core/ext/filters/client_channel/subchannel_stream_client.cc \
src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/service_config_parser.cc \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/http/client/http_client_filter.cc \ src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/http_filters_plugin.cc \
@ -1784,6 +1784,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/client_channel_channelz.cc \ src/core/ext/filters/client_channel/client_channel_channelz.cc \
src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/client_channel_service_config.cc \
src/core/ext/filters/client_channel/config_selector.cc \ src/core/ext/filters/client_channel/config_selector.cc \
src/core/ext/filters/client_channel/dynamic_filters.cc \ src/core/ext/filters/client_channel/dynamic_filters.cc \
src/core/ext/filters/client_channel/global_subchannel_pool.cc \ src/core/ext/filters/client_channel/global_subchannel_pool.cc \
@ -1817,7 +1818,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \
src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \
@ -1827,7 +1827,7 @@ LIBGRPC_UNSECURE_SRC = \
src/core/ext/filters/client_channel/subchannel_stream_client.cc \ src/core/ext/filters/client_channel/subchannel_stream_client.cc \
src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/service_config_parser.cc \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/http/client/http_client_filter.cc \ src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/http_filters_plugin.cc \
@ -2016,7 +2016,6 @@ LIBGRPC_UNSECURE_SRC = \
src/core/lib/iomgr/wakeup_fd_posix.cc \ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/json/json_object_loader.cc \ src/core/lib/json/json_object_loader.cc \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \
src/core/lib/json/json_util.cc \
src/core/lib/json/json_writer.cc \ src/core/lib/json/json_writer.cc \
src/core/lib/load_balancing/lb_policy.cc \ src/core/lib/load_balancing/lb_policy.cc \
src/core/lib/load_balancing/lb_policy_registry.cc \ src/core/lib/load_balancing/lb_policy_registry.cc \
@ -3185,6 +3184,7 @@ src/core/ext/xds/xds_routing.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_server_config_fetcher.cc: $(OPENSSL_DEP) src/core/ext/xds/xds_server_config_fetcher.cc: $(OPENSSL_DEP)
src/core/ext/xds/xds_transport_grpc.cc: $(OPENSSL_DEP) src/core/ext/xds/xds_transport_grpc.cc: $(OPENSSL_DEP)
src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP) src/core/lib/http/httpcli_security_connector.cc: $(OPENSSL_DEP)
src/core/lib/json/json_util.cc: $(OPENSSL_DEP)
src/core/lib/matchers/matchers.cc: $(OPENSSL_DEP) src/core/lib/matchers/matchers.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/grpc_authorization_engine.cc: $(OPENSSL_DEP) src/core/lib/security/authorization/grpc_authorization_engine.cc: $(OPENSSL_DEP)
src/core/lib/security/authorization/matchers.cc: $(OPENSSL_DEP) src/core/lib/security/authorization/matchers.cc: $(OPENSSL_DEP)

@ -329,6 +329,7 @@ libs:
- src/core/ext/filters/client_channel/client_channel.h - src/core/ext/filters/client_channel/client_channel.h
- src/core/ext/filters/client_channel/client_channel_channelz.h - src/core/ext/filters/client_channel/client_channel_channelz.h
- src/core/ext/filters/client_channel/client_channel_factory.h - src/core/ext/filters/client_channel/client_channel_factory.h
- src/core/ext/filters/client_channel/client_channel_service_config.h
- src/core/ext/filters/client_channel/config_selector.h - src/core/ext/filters/client_channel/config_selector.h
- src/core/ext/filters/client_channel/connector.h - src/core/ext/filters/client_channel/connector.h
- src/core/ext/filters/client_channel/dynamic_filters.h - src/core/ext/filters/client_channel/dynamic_filters.h
@ -356,7 +357,6 @@ libs:
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
- src/core/ext/filters/client_channel/resolver/polling_resolver.h - src/core/ext/filters/client_channel/resolver/polling_resolver.h
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h - src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h
- src/core/ext/filters/client_channel/resolver_result_parsing.h
- src/core/ext/filters/client_channel/retry_filter.h - src/core/ext/filters/client_channel/retry_filter.h
- src/core/ext/filters/client_channel/retry_service_config.h - src/core/ext/filters/client_channel/retry_service_config.h
- src/core/ext/filters/client_channel/retry_throttle.h - src/core/ext/filters/client_channel/retry_throttle.h
@ -366,7 +366,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.h - src/core/ext/filters/client_channel/subchannel_stream_client.h
- src/core/ext/filters/deadline/deadline_filter.h - src/core/ext/filters/deadline/deadline_filter.h
- src/core/ext/filters/fault_injection/fault_injection_filter.h - src/core/ext/filters/fault_injection/fault_injection_filter.h
- src/core/ext/filters/fault_injection/service_config_parser.h - src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h
- src/core/ext/filters/http/client/http_client_filter.h - src/core/ext/filters/http/client/http_client_filter.h
- src/core/ext/filters/http/client_authority_filter.h - src/core/ext/filters/http/client_authority_filter.h
- src/core/ext/filters/http/message_compress/message_compress_filter.h - src/core/ext/filters/http/message_compress/message_compress_filter.h
@ -869,6 +869,7 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.h - src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/json/json.h - src/core/lib/json/json.h
- src/core/lib/json/json_args.h - src/core/lib/json/json_args.h
- src/core/lib/json/json_channel_args.h
- src/core/lib/json/json_object_loader.h - src/core/lib/json/json_object_loader.h
- src/core/lib/json/json_util.h - src/core/lib/json/json_util.h
- src/core/lib/load_balancing/lb_policy.h - src/core/lib/load_balancing/lb_policy.h
@ -1048,6 +1049,7 @@ libs:
- src/core/ext/filters/client_channel/client_channel_channelz.cc - src/core/ext/filters/client_channel/client_channel_channelz.cc
- src/core/ext/filters/client_channel/client_channel_factory.cc - src/core/ext/filters/client_channel/client_channel_factory.cc
- src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/client_channel_plugin.cc
- src/core/ext/filters/client_channel/client_channel_service_config.cc
- src/core/ext/filters/client_channel/config_selector.cc - src/core/ext/filters/client_channel/config_selector.cc
- src/core/ext/filters/client_channel/dynamic_filters.cc - src/core/ext/filters/client_channel/dynamic_filters.cc
- src/core/ext/filters/client_channel/global_subchannel_pool.cc - src/core/ext/filters/client_channel/global_subchannel_pool.cc
@ -1089,7 +1091,6 @@ libs:
- src/core/ext/filters/client_channel/resolver/polling_resolver.cc - src/core/ext/filters/client_channel/resolver/polling_resolver.cc
- src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
- src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc - src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc
- src/core/ext/filters/client_channel/resolver_result_parsing.cc
- src/core/ext/filters/client_channel/retry_filter.cc - src/core/ext/filters/client_channel/retry_filter.cc
- src/core/ext/filters/client_channel/retry_service_config.cc - src/core/ext/filters/client_channel/retry_service_config.cc
- src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/retry_throttle.cc
@ -1099,7 +1100,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.cc - src/core/ext/filters/client_channel/subchannel_stream_client.cc
- src/core/ext/filters/deadline/deadline_filter.cc - src/core/ext/filters/deadline/deadline_filter.cc
- src/core/ext/filters/fault_injection/fault_injection_filter.cc - src/core/ext/filters/fault_injection/fault_injection_filter.cc
- src/core/ext/filters/fault_injection/service_config_parser.cc - src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
- src/core/ext/filters/http/client/http_client_filter.cc - src/core/ext/filters/http/client/http_client_filter.cc
- src/core/ext/filters/http/client_authority_filter.cc - src/core/ext/filters/http/client_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc - src/core/ext/filters/http/http_filters_plugin.cc
@ -1886,6 +1887,7 @@ libs:
- src/core/ext/filters/client_channel/client_channel.h - src/core/ext/filters/client_channel/client_channel.h
- src/core/ext/filters/client_channel/client_channel_channelz.h - src/core/ext/filters/client_channel/client_channel_channelz.h
- src/core/ext/filters/client_channel/client_channel_factory.h - src/core/ext/filters/client_channel/client_channel_factory.h
- src/core/ext/filters/client_channel/client_channel_service_config.h
- src/core/ext/filters/client_channel/config_selector.h - src/core/ext/filters/client_channel/config_selector.h
- src/core/ext/filters/client_channel/connector.h - src/core/ext/filters/client_channel/connector.h
- src/core/ext/filters/client_channel/dynamic_filters.h - src/core/ext/filters/client_channel/dynamic_filters.h
@ -1910,7 +1912,6 @@ libs:
- src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h - src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.h
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h
- src/core/ext/filters/client_channel/resolver/polling_resolver.h - src/core/ext/filters/client_channel/resolver/polling_resolver.h
- src/core/ext/filters/client_channel/resolver_result_parsing.h
- src/core/ext/filters/client_channel/retry_filter.h - src/core/ext/filters/client_channel/retry_filter.h
- src/core/ext/filters/client_channel/retry_service_config.h - src/core/ext/filters/client_channel/retry_service_config.h
- src/core/ext/filters/client_channel/retry_throttle.h - src/core/ext/filters/client_channel/retry_throttle.h
@ -1920,7 +1921,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.h - src/core/ext/filters/client_channel/subchannel_stream_client.h
- src/core/ext/filters/deadline/deadline_filter.h - src/core/ext/filters/deadline/deadline_filter.h
- src/core/ext/filters/fault_injection/fault_injection_filter.h - src/core/ext/filters/fault_injection/fault_injection_filter.h
- src/core/ext/filters/fault_injection/service_config_parser.h - src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h
- src/core/ext/filters/http/client/http_client_filter.h - src/core/ext/filters/http/client/http_client_filter.h
- src/core/ext/filters/http/client_authority_filter.h - src/core/ext/filters/http/client_authority_filter.h
- src/core/ext/filters/http/message_compress/message_compress_filter.h - src/core/ext/filters/http/message_compress/message_compress_filter.h
@ -2125,8 +2126,8 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.h - src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/json/json.h - src/core/lib/json/json.h
- src/core/lib/json/json_args.h - src/core/lib/json/json_args.h
- src/core/lib/json/json_channel_args.h
- src/core/lib/json/json_object_loader.h - src/core/lib/json/json_object_loader.h
- src/core/lib/json/json_util.h
- src/core/lib/load_balancing/lb_policy.h - src/core/lib/load_balancing/lb_policy.h
- src/core/lib/load_balancing/lb_policy_factory.h - src/core/lib/load_balancing/lb_policy_factory.h
- src/core/lib/load_balancing/lb_policy_registry.h - src/core/lib/load_balancing/lb_policy_registry.h
@ -2252,6 +2253,7 @@ libs:
- src/core/ext/filters/client_channel/client_channel_channelz.cc - src/core/ext/filters/client_channel/client_channel_channelz.cc
- src/core/ext/filters/client_channel/client_channel_factory.cc - src/core/ext/filters/client_channel/client_channel_factory.cc
- src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/client_channel_plugin.cc
- src/core/ext/filters/client_channel/client_channel_service_config.cc
- src/core/ext/filters/client_channel/config_selector.cc - src/core/ext/filters/client_channel/config_selector.cc
- src/core/ext/filters/client_channel/dynamic_filters.cc - src/core/ext/filters/client_channel/dynamic_filters.cc
- src/core/ext/filters/client_channel/global_subchannel_pool.cc - src/core/ext/filters/client_channel/global_subchannel_pool.cc
@ -2285,7 +2287,6 @@ libs:
- src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc - src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc
- src/core/ext/filters/client_channel/resolver/polling_resolver.cc - src/core/ext/filters/client_channel/resolver/polling_resolver.cc
- src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc - src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc
- src/core/ext/filters/client_channel/resolver_result_parsing.cc
- src/core/ext/filters/client_channel/retry_filter.cc - src/core/ext/filters/client_channel/retry_filter.cc
- src/core/ext/filters/client_channel/retry_service_config.cc - src/core/ext/filters/client_channel/retry_service_config.cc
- src/core/ext/filters/client_channel/retry_throttle.cc - src/core/ext/filters/client_channel/retry_throttle.cc
@ -2295,7 +2296,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.cc - src/core/ext/filters/client_channel/subchannel_stream_client.cc
- src/core/ext/filters/deadline/deadline_filter.cc - src/core/ext/filters/deadline/deadline_filter.cc
- src/core/ext/filters/fault_injection/fault_injection_filter.cc - src/core/ext/filters/fault_injection/fault_injection_filter.cc
- src/core/ext/filters/fault_injection/service_config_parser.cc - src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc
- src/core/ext/filters/http/client/http_client_filter.cc - src/core/ext/filters/http/client/http_client_filter.cc
- src/core/ext/filters/http/client_authority_filter.cc - src/core/ext/filters/http/client_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc - src/core/ext/filters/http/http_filters_plugin.cc
@ -2484,7 +2485,6 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.cc - src/core/lib/iomgr/wakeup_fd_posix.cc
- src/core/lib/json/json_object_loader.cc - src/core/lib/json/json_object_loader.cc
- src/core/lib/json/json_reader.cc - src/core/lib/json/json_reader.cc
- src/core/lib/json/json_util.cc
- src/core/lib/json/json_writer.cc - src/core/lib/json/json_writer.cc
- src/core/lib/load_balancing/lb_policy.cc - src/core/lib/load_balancing/lb_policy.cc
- src/core/lib/load_balancing/lb_policy_registry.cc - src/core/lib/load_balancing/lb_policy_registry.cc
@ -5187,6 +5187,15 @@ targets:
- test/cpp/end2end/test_service_impl.cc - test/cpp/end2end/test_service_impl.cc
deps: deps:
- grpc++_test_util - grpc++_test_util
- name: client_channel_service_config_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/client_channel/client_channel_service_config_test.cc
deps:
- grpc_test_util
- name: client_channel_stress_test - name: client_channel_stress_test
gtest: true gtest: true
build: test build: test
@ -8042,6 +8051,15 @@ targets:
deps: deps:
- grpc_test_util - grpc_test_util
uses_polling: false uses_polling: false
- name: message_size_service_config_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/message_size/message_size_service_config_test.cc
deps:
- grpc_test_util
- name: metadata_map_test - name: metadata_map_test
gtest: true gtest: true
build: test build: test
@ -9065,6 +9083,15 @@ targets:
deps: deps:
- grpc_test_util_unsecure - grpc_test_util_unsecure
uses_polling: false uses_polling: false
- name: retry_service_config_test
gtest: true
build: test
language: c++
headers: []
src:
- test/core/client_channel/retry_service_config_test.cc
deps:
- grpc_test_util
- name: retry_throttle_test - name: retry_throttle_test
gtest: true gtest: true
build: test build: test
@ -9487,7 +9514,7 @@ targets:
language: c++ language: c++
headers: [] headers: []
src: src:
- test/core/client_channel/service_config_test.cc - test/core/service_config/service_config_test.cc
deps: deps:
- grpc_test_util - grpc_test_util
- name: settings_timeout_test - name: settings_timeout_test

4
config.m4 generated

@ -50,6 +50,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/client_channel_channelz.cc \ src/core/ext/filters/client_channel/client_channel_channelz.cc \
src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_plugin.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/client_channel_service_config.cc \
src/core/ext/filters/client_channel/config_selector.cc \ src/core/ext/filters/client_channel/config_selector.cc \
src/core/ext/filters/client_channel/dynamic_filters.cc \ src/core/ext/filters/client_channel/dynamic_filters.cc \
src/core/ext/filters/client_channel/global_subchannel_pool.cc \ src/core/ext/filters/client_channel/global_subchannel_pool.cc \
@ -91,7 +92,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/resolver/polling_resolver.cc \ src/core/ext/filters/client_channel/resolver/polling_resolver.cc \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \
src/core/ext/filters/client_channel/retry_throttle.cc \ src/core/ext/filters/client_channel/retry_throttle.cc \
@ -101,7 +101,7 @@ if test "$PHP_GRPC" != "no"; then
src/core/ext/filters/client_channel/subchannel_stream_client.cc \ src/core/ext/filters/client_channel/subchannel_stream_client.cc \
src/core/ext/filters/deadline/deadline_filter.cc \ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/service_config_parser.cc \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/http/client/http_client_filter.cc \ src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/client_authority_filter.cc \
src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/http_filters_plugin.cc \

4
config.w32 generated

@ -16,6 +16,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\client_channel_channelz.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_channelz.cc " +
"src\\core\\ext\\filters\\client_channel\\client_channel_factory.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_factory.cc " +
"src\\core\\ext\\filters\\client_channel\\client_channel_plugin.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_plugin.cc " +
"src\\core\\ext\\filters\\client_channel\\client_channel_service_config.cc " +
"src\\core\\ext\\filters\\client_channel\\config_selector.cc " + "src\\core\\ext\\filters\\client_channel\\config_selector.cc " +
"src\\core\\ext\\filters\\client_channel\\dynamic_filters.cc " + "src\\core\\ext\\filters\\client_channel\\dynamic_filters.cc " +
"src\\core\\ext\\filters\\client_channel\\global_subchannel_pool.cc " + "src\\core\\ext\\filters\\client_channel\\global_subchannel_pool.cc " +
@ -57,7 +58,6 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\resolver\\polling_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\polling_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\sockaddr\\sockaddr_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\xds\\xds_resolver.cc " +
"src\\core\\ext\\filters\\client_channel\\resolver_result_parsing.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_filter.cc " + "src\\core\\ext\\filters\\client_channel\\retry_filter.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_service_config.cc " + "src\\core\\ext\\filters\\client_channel\\retry_service_config.cc " +
"src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " + "src\\core\\ext\\filters\\client_channel\\retry_throttle.cc " +
@ -67,7 +67,7 @@ if (PHP_GRPC != "no") {
"src\\core\\ext\\filters\\client_channel\\subchannel_stream_client.cc " + "src\\core\\ext\\filters\\client_channel\\subchannel_stream_client.cc " +
"src\\core\\ext\\filters\\deadline\\deadline_filter.cc " + "src\\core\\ext\\filters\\deadline\\deadline_filter.cc " +
"src\\core\\ext\\filters\\fault_injection\\fault_injection_filter.cc " + "src\\core\\ext\\filters\\fault_injection\\fault_injection_filter.cc " +
"src\\core\\ext\\filters\\fault_injection\\service_config_parser.cc " + "src\\core\\ext\\filters\\fault_injection\\fault_injection_service_config_parser.cc " +
"src\\core\\ext\\filters\\http\\client\\http_client_filter.cc " + "src\\core\\ext\\filters\\http\\client\\http_client_filter.cc " +
"src\\core\\ext\\filters\\http\\client_authority_filter.cc " + "src\\core\\ext\\filters\\http\\client_authority_filter.cc " +
"src\\core\\ext\\filters\\http\\http_filters_plugin.cc " + "src\\core\\ext\\filters\\http\\http_filters_plugin.cc " +

10
gRPC-C++.podspec generated

@ -231,6 +231,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_channelz.h', 'src/core/ext/filters/client_channel/client_channel_channelz.h',
'src/core/ext/filters/client_channel/client_channel_factory.h', 'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/client_channel_service_config.h',
'src/core/ext/filters/client_channel/config_selector.h', 'src/core/ext/filters/client_channel/config_selector.h',
'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/dynamic_filters.h', 'src/core/ext/filters/client_channel/dynamic_filters.h',
@ -258,7 +259,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h',
'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_service_config.h', 'src/core/ext/filters/client_channel/retry_service_config.h',
'src/core/ext/filters/client_channel/retry_throttle.h', 'src/core/ext/filters/client_channel/retry_throttle.h',
@ -268,7 +268,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel_stream_client.h', 'src/core/ext/filters/client_channel/subchannel_stream_client.h',
'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.h', 'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/service_config_parser.h', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h', 'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@ -832,6 +832,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h', 'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.h', 'src/core/lib/json/json.h',
'src/core/lib/json/json_args.h', 'src/core/lib/json/json_args.h',
'src/core/lib/json/json_channel_args.h',
'src/core/lib/json/json_object_loader.h', 'src/core/lib/json/json_object_loader.h',
'src/core/lib/json/json_util.h', 'src/core/lib/json/json_util.h',
'src/core/lib/load_balancing/lb_policy.h', 'src/core/lib/load_balancing/lb_policy.h',
@ -1125,6 +1126,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_channelz.h', 'src/core/ext/filters/client_channel/client_channel_channelz.h',
'src/core/ext/filters/client_channel/client_channel_factory.h', 'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/client_channel_service_config.h',
'src/core/ext/filters/client_channel/config_selector.h', 'src/core/ext/filters/client_channel/config_selector.h',
'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/dynamic_filters.h', 'src/core/ext/filters/client_channel/dynamic_filters.h',
@ -1152,7 +1154,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h',
'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_service_config.h', 'src/core/ext/filters/client_channel/retry_service_config.h',
'src/core/ext/filters/client_channel/retry_throttle.h', 'src/core/ext/filters/client_channel/retry_throttle.h',
@ -1162,7 +1163,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel_stream_client.h', 'src/core/ext/filters/client_channel/subchannel_stream_client.h',
'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.h', 'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/service_config_parser.h', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h', 'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@ -1708,6 +1709,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h', 'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.h', 'src/core/lib/json/json.h',
'src/core/lib/json/json_args.h', 'src/core/lib/json/json_args.h',
'src/core/lib/json/json_channel_args.h',
'src/core/lib/json/json_object_loader.h', 'src/core/lib/json/json_object_loader.h',
'src/core/lib/json/json_util.h', 'src/core/lib/json/json_util.h',
'src/core/lib/load_balancing/lb_policy.h', 'src/core/lib/load_balancing/lb_policy.h',

14
gRPC-Core.podspec generated

@ -216,6 +216,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_factory.h', 'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/client_channel_plugin.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/client_channel_service_config.cc',
'src/core/ext/filters/client_channel/client_channel_service_config.h',
'src/core/ext/filters/client_channel/config_selector.cc', 'src/core/ext/filters/client_channel/config_selector.cc',
'src/core/ext/filters/client_channel/config_selector.h', 'src/core/ext/filters/client_channel/config_selector.h',
'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/connector.h',
@ -284,8 +286,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h',
'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_service_config.cc', 'src/core/ext/filters/client_channel/retry_service_config.cc',
@ -304,8 +304,8 @@ Pod::Spec.new do |s|
'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.cc', 'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
'src/core/ext/filters/fault_injection/fault_injection_filter.h', 'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/service_config_parser.cc', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
'src/core/ext/filters/fault_injection/service_config_parser.h', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.cc', 'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/client_authority_filter.cc',
@ -1353,6 +1353,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h', 'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.h', 'src/core/lib/json/json.h',
'src/core/lib/json/json_args.h', 'src/core/lib/json/json_args.h',
'src/core/lib/json/json_channel_args.h',
'src/core/lib/json/json_object_loader.cc', 'src/core/lib/json/json_object_loader.cc',
'src/core/lib/json/json_object_loader.h', 'src/core/lib/json/json_object_loader.h',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
@ -1783,6 +1784,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel.h',
'src/core/ext/filters/client_channel/client_channel_channelz.h', 'src/core/ext/filters/client_channel/client_channel_channelz.h',
'src/core/ext/filters/client_channel/client_channel_factory.h', 'src/core/ext/filters/client_channel/client_channel_factory.h',
'src/core/ext/filters/client_channel/client_channel_service_config.h',
'src/core/ext/filters/client_channel/config_selector.h', 'src/core/ext/filters/client_channel/config_selector.h',
'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/connector.h',
'src/core/ext/filters/client_channel/dynamic_filters.h', 'src/core/ext/filters/client_channel/dynamic_filters.h',
@ -1810,7 +1812,6 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h',
'src/core/ext/filters/client_channel/resolver/polling_resolver.h', 'src/core/ext/filters/client_channel/resolver/polling_resolver.h',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h',
'src/core/ext/filters/client_channel/resolver_result_parsing.h',
'src/core/ext/filters/client_channel/retry_filter.h', 'src/core/ext/filters/client_channel/retry_filter.h',
'src/core/ext/filters/client_channel/retry_service_config.h', 'src/core/ext/filters/client_channel/retry_service_config.h',
'src/core/ext/filters/client_channel/retry_throttle.h', 'src/core/ext/filters/client_channel/retry_throttle.h',
@ -1820,7 +1821,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel_stream_client.h', 'src/core/ext/filters/client_channel/subchannel_stream_client.h',
'src/core/ext/filters/deadline/deadline_filter.h', 'src/core/ext/filters/deadline/deadline_filter.h',
'src/core/ext/filters/fault_injection/fault_injection_filter.h', 'src/core/ext/filters/fault_injection/fault_injection_filter.h',
'src/core/ext/filters/fault_injection/service_config_parser.h', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h',
'src/core/ext/filters/http/client/http_client_filter.h', 'src/core/ext/filters/http/client/http_client_filter.h',
'src/core/ext/filters/http/client_authority_filter.h', 'src/core/ext/filters/http/client_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h', 'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@ -2346,6 +2347,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h', 'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.h', 'src/core/lib/json/json.h',
'src/core/lib/json/json_args.h', 'src/core/lib/json/json_args.h',
'src/core/lib/json/json_channel_args.h',
'src/core/lib/json/json_object_loader.h', 'src/core/lib/json/json_object_loader.h',
'src/core/lib/json/json_util.h', 'src/core/lib/json/json_util.h',
'src/core/lib/load_balancing/lb_policy.h', 'src/core/lib/load_balancing/lb_policy.h',

9
grpc.gemspec generated

@ -127,6 +127,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.cc )
s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h )
s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.cc )
s.files += %w( src/core/ext/filters/client_channel/client_channel_service_config.cc )
s.files += %w( src/core/ext/filters/client_channel/client_channel_service_config.h )
s.files += %w( src/core/ext/filters/client_channel/config_selector.cc ) s.files += %w( src/core/ext/filters/client_channel/config_selector.cc )
s.files += %w( src/core/ext/filters/client_channel/config_selector.h ) s.files += %w( src/core/ext/filters/client_channel/config_selector.h )
s.files += %w( src/core/ext/filters/client_channel/connector.h ) s.files += %w( src/core/ext/filters/client_channel/connector.h )
@ -195,8 +197,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h )
s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.cc )
s.files += %w( src/core/ext/filters/client_channel/resolver_result_parsing.h )
s.files += %w( src/core/ext/filters/client_channel/retry_filter.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_filter.cc )
s.files += %w( src/core/ext/filters/client_channel/retry_filter.h ) s.files += %w( src/core/ext/filters/client_channel/retry_filter.h )
s.files += %w( src/core/ext/filters/client_channel/retry_service_config.cc ) s.files += %w( src/core/ext/filters/client_channel/retry_service_config.cc )
@ -215,8 +215,8 @@ Gem::Specification.new do |s|
s.files += %w( src/core/ext/filters/deadline/deadline_filter.h ) s.files += %w( src/core/ext/filters/deadline/deadline_filter.h )
s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.cc ) s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.cc )
s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.h ) s.files += %w( src/core/ext/filters/fault_injection/fault_injection_filter.h )
s.files += %w( src/core/ext/filters/fault_injection/service_config_parser.cc ) s.files += %w( src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc )
s.files += %w( src/core/ext/filters/fault_injection/service_config_parser.h ) s.files += %w( src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.cc ) s.files += %w( src/core/ext/filters/http/client/http_client_filter.cc )
s.files += %w( src/core/ext/filters/http/client/http_client_filter.h ) s.files += %w( src/core/ext/filters/http/client/http_client_filter.h )
s.files += %w( src/core/ext/filters/http/client_authority_filter.cc ) s.files += %w( src/core/ext/filters/http/client_authority_filter.cc )
@ -1264,6 +1264,7 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.h ) s.files += %w( src/core/lib/iomgr/wakeup_fd_posix.h )
s.files += %w( src/core/lib/json/json.h ) s.files += %w( src/core/lib/json/json.h )
s.files += %w( src/core/lib/json/json_args.h ) s.files += %w( src/core/lib/json/json_args.h )
s.files += %w( src/core/lib/json/json_channel_args.h )
s.files += %w( src/core/lib/json/json_object_loader.cc ) s.files += %w( src/core/lib/json/json_object_loader.cc )
s.files += %w( src/core/lib/json/json_object_loader.h ) s.files += %w( src/core/lib/json/json_object_loader.h )
s.files += %w( src/core/lib/json/json_reader.cc ) s.files += %w( src/core/lib/json/json_reader.cc )

9
grpc.gyp generated

@ -382,6 +382,7 @@
'src/core/ext/filters/client_channel/client_channel_channelz.cc', 'src/core/ext/filters/client_channel/client_channel_channelz.cc',
'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/client_channel_service_config.cc',
'src/core/ext/filters/client_channel/config_selector.cc', 'src/core/ext/filters/client_channel/config_selector.cc',
'src/core/ext/filters/client_channel/dynamic_filters.cc', 'src/core/ext/filters/client_channel/dynamic_filters.cc',
'src/core/ext/filters/client_channel/global_subchannel_pool.cc', 'src/core/ext/filters/client_channel/global_subchannel_pool.cc',
@ -423,7 +424,6 @@
'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc',
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_service_config.cc', 'src/core/ext/filters/client_channel/retry_service_config.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc',
@ -433,7 +433,7 @@
'src/core/ext/filters/client_channel/subchannel_stream_client.cc', 'src/core/ext/filters/client_channel/subchannel_stream_client.cc',
'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/fault_injection/fault_injection_filter.cc', 'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
'src/core/ext/filters/fault_injection/service_config_parser.cc', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
'src/core/ext/filters/http/client/http_client_filter.cc', 'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/http_filters_plugin.cc',
@ -1145,6 +1145,7 @@
'src/core/ext/filters/client_channel/client_channel_channelz.cc', 'src/core/ext/filters/client_channel/client_channel_channelz.cc',
'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/client_channel_service_config.cc',
'src/core/ext/filters/client_channel/config_selector.cc', 'src/core/ext/filters/client_channel/config_selector.cc',
'src/core/ext/filters/client_channel/dynamic_filters.cc', 'src/core/ext/filters/client_channel/dynamic_filters.cc',
'src/core/ext/filters/client_channel/global_subchannel_pool.cc', 'src/core/ext/filters/client_channel/global_subchannel_pool.cc',
@ -1178,7 +1179,6 @@
'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc',
'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc',
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_service_config.cc', 'src/core/ext/filters/client_channel/retry_service_config.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc',
@ -1188,7 +1188,7 @@
'src/core/ext/filters/client_channel/subchannel_stream_client.cc', 'src/core/ext/filters/client_channel/subchannel_stream_client.cc',
'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/fault_injection/fault_injection_filter.cc', 'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
'src/core/ext/filters/fault_injection/service_config_parser.cc', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
'src/core/ext/filters/http/client/http_client_filter.cc', 'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/http_filters_plugin.cc',
@ -1377,7 +1377,6 @@
'src/core/lib/iomgr/wakeup_fd_posix.cc', 'src/core/lib/iomgr/wakeup_fd_posix.cc',
'src/core/lib/json/json_object_loader.cc', 'src/core/lib/json/json_object_loader.cc',
'src/core/lib/json/json_reader.cc', 'src/core/lib/json/json_reader.cc',
'src/core/lib/json/json_util.cc',
'src/core/lib/json/json_writer.cc', 'src/core/lib/json/json_writer.cc',
'src/core/lib/load_balancing/lb_policy.cc', 'src/core/lib/load_balancing/lb_policy.cc',
'src/core/lib/load_balancing/lb_policy_registry.cc', 'src/core/lib/load_balancing/lb_policy_registry.cc',

9
package.xml generated

@ -109,6 +109,8 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_factory.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_plugin.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_plugin.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_service_config.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/client_channel_service_config.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/config_selector.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/config_selector.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/config_selector.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/config_selector.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/connector.h" role="src" />
@ -177,8 +179,6 @@
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/resolver_result_parsing.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_service_config.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/client_channel/retry_service_config.cc" role="src" />
@ -197,8 +197,8 @@
<file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/deadline/deadline_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/service_config_parser.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/fault_injection/service_config_parser.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.cc" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/http/client/http_client_filter.h" role="src" />
<file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.cc" role="src" /> <file baseinstalldir="/" name="src/core/ext/filters/http/client_authority_filter.cc" role="src" />
@ -1246,6 +1246,7 @@
<file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_posix.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/iomgr/wakeup_fd_posix.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_args.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json_args.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_channel_args.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_object_loader.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json_object_loader.cc" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_object_loader.h" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json_object_loader.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_reader.cc" role="src" /> <file baseinstalldir="/" name="src/core/lib/json/json_reader.cc" role="src" />

@ -2058,15 +2058,12 @@ grpc_cc_library(
hdrs = [ hdrs = [
"lib/service_config/service_config_parser.h", "lib/service_config/service_config_parser.h",
], ],
external_deps = [ external_deps = ["absl/strings"],
"absl/status",
"absl/status:statusor",
"absl/strings",
],
language = "c++", language = "c++",
deps = [ deps = [
"channel_args", "channel_args",
"json", "json",
"validation_errors",
"//:gpr", "//:gpr",
], ],
) )
@ -3056,7 +3053,6 @@ grpc_cc_library(
], ],
external_deps = [ external_deps = [
"absl/status", "absl/status",
"absl/status:statusor",
"absl/strings", "absl/strings",
"absl/strings:str_format", "absl/strings:str_format",
"absl/types:optional", "absl/types:optional",
@ -3070,9 +3066,12 @@ grpc_cc_library(
"closure", "closure",
"grpc_service_config", "grpc_service_config",
"json", "json",
"json_args",
"json_object_loader",
"service_config_parser", "service_config_parser",
"slice_buffer", "slice_buffer",
"status_helper", "status_helper",
"validation_errors",
"//:channel_stack_builder", "//:channel_stack_builder",
"//:config", "//:config",
"//:debug_location", "//:debug_location",
@ -3086,11 +3085,11 @@ grpc_cc_library(
name = "grpc_fault_injection_filter", name = "grpc_fault_injection_filter",
srcs = [ srcs = [
"ext/filters/fault_injection/fault_injection_filter.cc", "ext/filters/fault_injection/fault_injection_filter.cc",
"ext/filters/fault_injection/service_config_parser.cc", "ext/filters/fault_injection/fault_injection_service_config_parser.cc",
], ],
hdrs = [ hdrs = [
"ext/filters/fault_injection/fault_injection_filter.h", "ext/filters/fault_injection/fault_injection_filter.h",
"ext/filters/fault_injection/service_config_parser.h", "ext/filters/fault_injection/fault_injection_service_config_parser.h",
], ],
external_deps = [ external_deps = [
"absl/base:core_headers", "absl/base:core_headers",
@ -3107,12 +3106,13 @@ grpc_cc_library(
"context", "context",
"grpc_service_config", "grpc_service_config",
"json", "json",
"json_util", "json_args",
"json_object_loader",
"service_config_parser", "service_config_parser",
"sleep", "sleep",
"status_helper",
"time", "time",
"try_seq", "try_seq",
"validation_errors",
"//:config", "//:config",
"//:gpr", "//:gpr",
"//:grpc_base", "//:grpc_base",
@ -3135,7 +3135,6 @@ grpc_cc_library(
"absl/status", "absl/status",
"absl/status:statusor", "absl/status:statusor",
"absl/strings", "absl/strings",
"absl/strings:str_format",
"absl/types:optional", "absl/types:optional",
], ],
language = "c++", language = "c++",
@ -3148,10 +3147,12 @@ grpc_cc_library(
"grpc_rbac_engine", "grpc_rbac_engine",
"grpc_service_config", "grpc_service_config",
"json", "json",
"json_util", "json_args",
"json_object_loader",
"service_config_parser", "service_config_parser",
"status_helper", "status_helper",
"transport_fwd", "transport_fwd",
"validation_errors",
"//:config", "//:config",
"//:debug_location", "//:debug_location",
"//:gpr", "//:gpr",

@ -47,12 +47,12 @@
#include "src/core/ext/filters/client_channel/backend_metric.h" #include "src/core/ext/filters/client_channel/backend_metric.h"
#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/ext/filters/client_channel/backup_poller.h"
#include "src/core/ext/filters/client_channel/client_channel_channelz.h" #include "src/core/ext/filters/client_channel/client_channel_channelz.h"
#include "src/core/ext/filters/client_channel/client_channel_service_config.h"
#include "src/core/ext/filters/client_channel/config_selector.h" #include "src/core/ext/filters/client_channel/config_selector.h"
#include "src/core/ext/filters/client_channel/dynamic_filters.h" #include "src/core/ext/filters/client_channel/dynamic_filters.h"
#include "src/core/ext/filters/client_channel/global_subchannel_pool.h" #include "src/core/ext/filters/client_channel/global_subchannel_pool.h"
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" #include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
#include "src/core/ext/filters/client_channel/local_subchannel_pool.h" #include "src/core/ext/filters/client_channel/local_subchannel_pool.h"
#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
#include "src/core/ext/filters/client_channel/retry_filter.h" #include "src/core/ext/filters/client_channel/retry_filter.h"
#include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface_internal.h" #include "src/core/ext/filters/client_channel/subchannel_interface_internal.h"

@ -19,7 +19,7 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/client_channel.h" #include "src/core/ext/filters/client_channel/client_channel.h"
#include "src/core/ext/filters/client_channel/resolver_result_parsing.h" #include "src/core/ext/filters/client_channel/client_channel_service_config.h"
#include "src/core/ext/filters/client_channel/retry_service_config.h" #include "src/core/ext/filters/client_channel/retry_service_config.h"
#include "src/core/lib/channel/channel_stack_builder.h" #include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"

@ -0,0 +1,153 @@
//
// Copyright 2018 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 <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/client_channel_service_config.h"
#include <map>
#include <utility>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/ascii.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
#include "src/core/lib/load_balancing/lb_policy_registry.h"
// As per the retry design, we do not allow more than 5 retry attempts.
#define MAX_MAX_RETRY_ATTEMPTS 5
namespace grpc_core {
namespace internal {
//
// ClientChannelGlobalParsedConfig::HealthCheckConfig
//
const JsonLoaderInterface*
ClientChannelGlobalParsedConfig::HealthCheckConfig::JsonLoader(
const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<HealthCheckConfig>()
.OptionalField("serviceName", &HealthCheckConfig::service_name)
.Finish();
return loader;
}
//
// ClientChannelGlobalParsedConfig
//
const JsonLoaderInterface* ClientChannelGlobalParsedConfig::JsonLoader(
const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<ClientChannelGlobalParsedConfig>()
// Note: "loadBalancingConfig" requires special handling, so
// that field will be parsed in JsonPostLoad() instead.
.OptionalField(
"loadBalancingPolicy",
&ClientChannelGlobalParsedConfig::parsed_deprecated_lb_policy_)
.OptionalField("healthCheckConfig",
&ClientChannelGlobalParsedConfig::health_check_config_)
.Finish();
return loader;
}
void ClientChannelGlobalParsedConfig::JsonPostLoad(const Json& json,
const JsonArgs&,
ValidationErrors* errors) {
const auto& lb_policy_registry =
CoreConfiguration::Get().lb_policy_registry();
// Parse LB config.
{
ValidationErrors::ScopedField field(errors, ".loadBalancingConfig");
auto it = json.object_value().find("loadBalancingConfig");
if (it != json.object_value().end()) {
auto config = lb_policy_registry.ParseLoadBalancingConfig(it->second);
if (!config.ok()) {
errors->AddError(config.status().message());
} else {
parsed_lb_config_ = std::move(*config);
}
}
}
// Sanity-check deprecated "loadBalancingPolicy" field.
if (!parsed_deprecated_lb_policy_.empty()) {
ValidationErrors::ScopedField field(errors, ".loadBalancingPolicy");
// Convert to lower-case.
absl::AsciiStrToLower(&parsed_deprecated_lb_policy_);
bool requires_config = false;
if (!lb_policy_registry.LoadBalancingPolicyExists(
parsed_deprecated_lb_policy_, &requires_config)) {
errors->AddError(absl::StrCat("unknown LB policy \"",
parsed_deprecated_lb_policy_, "\""));
} else if (requires_config) {
errors->AddError(absl::StrCat(
"LB policy \"", parsed_deprecated_lb_policy_,
"\" requires a config. Please use loadBalancingConfig instead."));
}
}
}
//
// ClientChannelMethodParsedConfig
//
const JsonLoaderInterface* ClientChannelMethodParsedConfig::JsonLoader(
const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<ClientChannelMethodParsedConfig>()
.OptionalField("timeout", &ClientChannelMethodParsedConfig::timeout_)
.OptionalField("waitForReady",
&ClientChannelMethodParsedConfig::wait_for_ready_)
.Finish();
return loader;
}
//
// ClientChannelServiceConfigParser
//
size_t ClientChannelServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
void ClientChannelServiceConfigParser::Register(
CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<ClientChannelServiceConfigParser>());
}
std::unique_ptr<ServiceConfigParser::ParsedConfig>
ClientChannelServiceConfigParser::ParseGlobalParams(const ChannelArgs& /*args*/,
const Json& json,
ValidationErrors* errors) {
return LoadFromJson<std::unique_ptr<ClientChannelGlobalParsedConfig>>(
json, JsonArgs(), errors);
}
std::unique_ptr<ServiceConfigParser::ParsedConfig>
ClientChannelServiceConfigParser::ParsePerMethodParams(
const ChannelArgs& /*args*/, const Json& json, ValidationErrors* errors) {
return LoadFromJson<std::unique_ptr<ClientChannelMethodParsedConfig>>(
json, JsonArgs(), errors);
}
} // namespace internal
} // namespace grpc_core

@ -14,8 +14,8 @@
// limitations under the License. // limitations under the License.
// //
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H #ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_SERVICE_CONFIG_H
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H #define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_SERVICE_CONFIG_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
@ -23,9 +23,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -33,7 +31,10 @@
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h" #include "src/core/lib/gprpp/time.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
#include "src/core/lib/json/json_object_loader.h"
#include "src/core/lib/load_balancing/lb_policy.h" #include "src/core/lib/load_balancing/lb_policy.h"
#include "src/core/lib/service_config/service_config_parser.h" #include "src/core/lib/service_config/service_config_parser.h"
@ -43,14 +44,6 @@ namespace internal {
class ClientChannelGlobalParsedConfig class ClientChannelGlobalParsedConfig
: public ServiceConfigParser::ParsedConfig { : public ServiceConfigParser::ParsedConfig {
public: public:
ClientChannelGlobalParsedConfig(
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config,
std::string parsed_deprecated_lb_policy,
absl::optional<std::string> health_check_service_name)
: parsed_lb_config_(std::move(parsed_lb_config)),
parsed_deprecated_lb_policy_(std::move(parsed_deprecated_lb_policy)),
health_check_service_name_(std::move(health_check_service_name)) {}
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const { RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config() const {
return parsed_lb_config_; return parsed_lb_config_;
} }
@ -60,26 +53,34 @@ class ClientChannelGlobalParsedConfig
} }
const absl::optional<std::string>& health_check_service_name() const { const absl::optional<std::string>& health_check_service_name() const {
return health_check_service_name_; return health_check_config_.service_name;
} }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
void JsonPostLoad(const Json& json, const JsonArgs&,
ValidationErrors* errors);
private: private:
struct HealthCheckConfig {
absl::optional<std::string> service_name;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
};
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_; RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
std::string parsed_deprecated_lb_policy_; std::string parsed_deprecated_lb_policy_;
absl::optional<std::string> health_check_service_name_; HealthCheckConfig health_check_config_;
}; };
class ClientChannelMethodParsedConfig class ClientChannelMethodParsedConfig
: public ServiceConfigParser::ParsedConfig { : public ServiceConfigParser::ParsedConfig {
public: public:
ClientChannelMethodParsedConfig(Duration timeout,
const absl::optional<bool>& wait_for_ready)
: timeout_(timeout), wait_for_ready_(wait_for_ready) {}
Duration timeout() const { return timeout_; } Duration timeout() const { return timeout_; }
absl::optional<bool> wait_for_ready() const { return wait_for_ready_; } absl::optional<bool> wait_for_ready() const { return wait_for_ready_; }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
private: private:
Duration timeout_; Duration timeout_;
absl::optional<bool> wait_for_ready_; absl::optional<bool> wait_for_ready_;
@ -89,11 +90,13 @@ class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
public: public:
absl::string_view name() const override { return parser_name(); } absl::string_view name() const override { return parser_name(); }
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
ParseGlobalParams(const ChannelArgs& /*args*/, const Json& json) override; const ChannelArgs& /*args*/, const Json& json,
ValidationErrors* errors) override;
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
ParsePerMethodParams(const ChannelArgs& /*args*/, const Json& json) override; const ChannelArgs& /*args*/, const Json& json,
ValidationErrors* errors) override;
static size_t ParserIndex(); static size_t ParserIndex();
static void Register(CoreConfiguration::Builder* builder); static void Register(CoreConfiguration::Builder* builder);
@ -105,4 +108,4 @@ class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
} // namespace internal } // namespace internal
} // namespace grpc_core } // namespace grpc_core
#endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H #endif // GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CLIENT_CHANNEL_SERVICE_CONFIG_H

@ -2426,13 +2426,8 @@ void RlsLbConfig::JsonPostLoad(const Json& json, const JsonArgs&,
if (it != json.object_value().end()) { if (it != json.object_value().end()) {
ValidationErrors::ScopedField field(errors, ValidationErrors::ScopedField field(errors,
".routeLookupChannelServiceConfig"); ".routeLookupChannelServiceConfig");
grpc_error_handle child_error; // Don't need to save the result here, just need the errors (if any).
rls_channel_service_config_ = it->second.Dump(); ServiceConfigImpl::Create(ChannelArgs(), it->second, errors);
auto service_config = MakeRefCounted<ServiceConfigImpl>(
ChannelArgs(), rls_channel_service_config_, it->second, &child_error);
if (!child_error.ok()) {
errors->AddError(StatusToString(child_error));
}
} }
// Validate childPolicyConfigTargetFieldName. // Validate childPolicyConfigTargetFieldName.
{ {

@ -1,186 +0,0 @@
//
// Copyright 2018 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 <grpc/support/port_platform.h>
#include "src/core/ext/filters/client_channel/resolver_result_parsing.h"
#include <ctype.h>
#include <algorithm>
#include <map>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
#include <grpc/support/log.h>
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json_util.h"
#include "src/core/lib/load_balancing/lb_policy_registry.h"
// As per the retry design, we do not allow more than 5 retry attempts.
#define MAX_MAX_RETRY_ATTEMPTS 5
namespace grpc_core {
namespace internal {
size_t ClientChannelServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
void ClientChannelServiceConfigParser::Register(
CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<ClientChannelServiceConfigParser>());
}
namespace {
absl::optional<std::string> ParseHealthCheckConfig(const Json& field,
grpc_error_handle* error) {
GPR_DEBUG_ASSERT(error != nullptr && error->ok());
if (field.type() != Json::Type::OBJECT) {
*error = GRPC_ERROR_CREATE(
"field:healthCheckConfig error:should be of type object");
return absl::nullopt;
}
std::vector<grpc_error_handle> error_list;
absl::optional<std::string> service_name;
auto it = field.object_value().find("serviceName");
if (it != field.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:serviceName error:should be of type string"));
} else {
service_name = it->second.string_value();
}
}
*error =
GRPC_ERROR_CREATE_FROM_VECTOR("field:healthCheckConfig", &error_list);
return service_name;
}
} // namespace
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
ClientChannelServiceConfigParser::ParseGlobalParams(const ChannelArgs& /*args*/,
const Json& json) {
std::vector<grpc_error_handle> error_list;
const auto& lb_policy_registry =
CoreConfiguration::Get().lb_policy_registry();
// Parse LB config.
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config;
auto it = json.object_value().find("loadBalancingConfig");
if (it != json.object_value().end()) {
auto config = lb_policy_registry.ParseLoadBalancingConfig(it->second);
if (!config.ok()) {
error_list.push_back(GRPC_ERROR_CREATE(absl::StrCat(
"field:loadBalancingConfig error:", config.status().message())));
} else {
parsed_lb_config = std::move(*config);
}
}
// Parse deprecated LB policy.
std::string lb_policy_name;
it = json.object_value().find("loadBalancingPolicy");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:loadBalancingPolicy error:type should be string"));
} else {
lb_policy_name = it->second.string_value();
for (size_t i = 0; i < lb_policy_name.size(); ++i) {
lb_policy_name[i] = tolower(lb_policy_name[i]);
}
bool requires_config = false;
if (!lb_policy_registry.LoadBalancingPolicyExists(lb_policy_name.c_str(),
&requires_config)) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:loadBalancingPolicy error:Unknown lb policy"));
} else if (requires_config) {
error_list.push_back(GRPC_ERROR_CREATE(
absl::StrCat("field:loadBalancingPolicy error:", lb_policy_name,
" requires a config. Please use loadBalancingConfig "
"instead.")));
}
}
}
// Parse health check config.
absl::optional<std::string> health_check_service_name;
it = json.object_value().find("healthCheckConfig");
if (it != json.object_value().end()) {
grpc_error_handle parsing_error;
health_check_service_name =
ParseHealthCheckConfig(it->second, &parsing_error);
if (!parsing_error.ok()) {
error_list.push_back(parsing_error);
}
}
if (!error_list.empty()) {
grpc_error_handle error = GRPC_ERROR_CREATE_FROM_VECTOR(
"Client channel global parser", &error_list);
absl::Status status = absl::InvalidArgumentError(
absl::StrCat("error parsing client channel global parameters: ",
StatusToString(error)));
return status;
}
return std::make_unique<ClientChannelGlobalParsedConfig>(
std::move(parsed_lb_config), std::move(lb_policy_name),
std::move(health_check_service_name));
}
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
ClientChannelServiceConfigParser::ParsePerMethodParams(
const ChannelArgs& /*args*/, const Json& json) {
std::vector<grpc_error_handle> error_list;
// Parse waitForReady.
absl::optional<bool> wait_for_ready;
auto it = json.object_value().find("waitForReady");
if (it != json.object_value().end()) {
if (it->second.type() == Json::Type::JSON_TRUE) {
wait_for_ready.emplace(true);
} else if (it->second.type() == Json::Type::JSON_FALSE) {
wait_for_ready.emplace(false);
} else {
error_list.push_back(GRPC_ERROR_CREATE(
"field:waitForReady error:Type should be true/false"));
}
}
// Parse timeout.
Duration timeout;
ParseJsonObjectFieldAsDuration(json.object_value(), "timeout", &timeout,
&error_list, false);
// Return result.
if (!error_list.empty()) {
grpc_error_handle error =
GRPC_ERROR_CREATE_FROM_VECTOR("Client channel parser", &error_list);
absl::Status status = absl::InvalidArgumentError(
absl::StrCat("error parsing client channel method parameters: ",
StatusToString(error)));
return status;
}
return std::make_unique<ClientChannelMethodParsedConfig>(timeout,
wait_for_ready);
}
} // namespace internal
} // namespace grpc_core

@ -18,16 +18,13 @@
#include "src/core/ext/filters/client_channel/retry_service_config.h" #include "src/core/ext/filters/client_channel/retry_service_config.h"
#include <stdio.h> #include <cstdint>
#include <string.h>
#include <algorithm>
#include <map> #include <map>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/status/status.h" #include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -38,10 +35,7 @@
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h" #include "src/core/lib/channel/status_util.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gpr/string.h" #include "src/core/lib/json/json_channel_args.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json_util.h"
// As per the retry design, we do not allow more than 5 retry attempts. // As per the retry design, we do not allow more than 5 retry attempts.
#define MAX_MAX_RETRY_ATTEMPTS 5 #define MAX_MAX_RETRY_ATTEMPTS 5
@ -49,271 +43,240 @@
namespace grpc_core { namespace grpc_core {
namespace internal { namespace internal {
size_t RetryServiceConfigParser::ParserIndex() { //
return CoreConfiguration::Get().service_config_parser().GetParserIndex( // RetryGlobalConfig
parser_name()); //
}
void RetryServiceConfigParser::Register(CoreConfiguration::Builder* builder) { const JsonLoaderInterface* RetryGlobalConfig::JsonLoader(const JsonArgs&) {
builder->service_config_parser()->RegisterParser( // Note: Both fields require custom processing, so they're handled in
std::make_unique<RetryServiceConfigParser>()); // JsonPostLoad() instead.
static const auto* loader = JsonObjectLoader<RetryGlobalConfig>().Finish();
return loader;
} }
namespace { void RetryGlobalConfig::JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors) {
grpc_error_handle ParseRetryThrottling(const Json& json,
intptr_t* max_milli_tokens,
intptr_t* milli_token_ratio) {
if (json.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE(
"field:retryThrottling error:Type should be object");
}
std::vector<grpc_error_handle> error_list;
// Parse maxTokens. // Parse maxTokens.
auto it = json.object_value().find("maxTokens"); auto max_tokens = LoadJsonObjectField<uint32_t>(json.object_value(), args,
if (it == json.object_value().end()) { "maxTokens", errors);
error_list.push_back(GRPC_ERROR_CREATE( if (max_tokens.has_value()) {
"field:retryThrottling field:maxTokens error:Not found")); ValidationErrors::ScopedField field(errors, ".maxTokens");
} else if (it->second.type() != Json::Type::NUMBER) { if (*max_tokens == 0) {
error_list.push_back(GRPC_ERROR_CREATE( errors->AddError("must be greater than 0");
"field:retryThrottling field:maxTokens error:Type should be "
"number"));
} else { } else {
*max_milli_tokens = // Multiply by 1000 to represent as milli-tokens.
gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000; max_milli_tokens_ = static_cast<uintptr_t>(*max_tokens) * 1000;
if (*max_milli_tokens <= 0) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:maxTokens error:should be "
"greater than zero"));
} }
} }
// Parse tokenRatio. // Parse tokenRatio.
it = json.object_value().find("tokenRatio"); ValidationErrors::ScopedField field(errors, ".tokenRatio");
auto it = json.object_value().find("tokenRatio");
if (it == json.object_value().end()) { if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE( errors->AddError("field not present");
"field:retryThrottling field:tokenRatio error:Not found")); return;
} else if (it->second.type() != Json::Type::NUMBER) { }
error_list.push_back(GRPC_ERROR_CREATE( if (it->second.type() != Json::Type::NUMBER &&
"field:retryThrottling field:tokenRatio error:type should be " it->second.type() != Json::Type::STRING) {
"number")); errors->AddError("is not a number");
} else { return;
// We support up to 3 decimal digits. }
size_t whole_len = it->second.string_value().size(); absl::string_view buf = it->second.string_value();
const char* value = it->second.string_value().c_str();
uint32_t multiplier = 1; uint32_t multiplier = 1;
uint32_t decimal_value = 0; uint32_t decimal_value = 0;
const char* decimal_point = strchr(value, '.'); auto decimal_point = buf.find('.');
if (decimal_point != nullptr) { if (decimal_point != absl::string_view::npos) {
whole_len = static_cast<size_t>(decimal_point - value); absl::string_view after_decimal = buf.substr(decimal_point + 1);
buf = buf.substr(0, decimal_point);
// We support up to 3 decimal digits.
multiplier = 1000; multiplier = 1000;
size_t decimal_len = strlen(decimal_point + 1); if (after_decimal.length() > 3) after_decimal = after_decimal.substr(0, 3);
if (decimal_len > 3) decimal_len = 3; // Parse decimal value.
if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len, if (!absl::SimpleAtoi(after_decimal, &decimal_value)) {
&decimal_value)) { errors->AddError("could not parse as a number");
error_list.push_back(GRPC_ERROR_CREATE( return;
"field:retryThrottling field:tokenRatio error:Failed "
"parsing"));
return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
} }
uint32_t decimal_multiplier = 1; uint32_t decimal_multiplier = 1;
for (size_t i = 0; i < (3 - decimal_len); ++i) { for (size_t i = 0; i < (3 - after_decimal.length()); ++i) {
decimal_multiplier *= 10; decimal_multiplier *= 10;
} }
decimal_value *= decimal_multiplier; decimal_value *= decimal_multiplier;
} }
uint32_t whole_value; uint32_t whole_value;
if (!gpr_parse_bytes_to_uint32(value, whole_len, &whole_value)) { if (!absl::SimpleAtoi(buf, &whole_value)) {
error_list.push_back(GRPC_ERROR_CREATE( errors->AddError("could not parse as a number");
"field:retryThrottling field:tokenRatio error:Failed " return;
"parsing"));
return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
} }
*milli_token_ratio = milli_token_ratio_ =
static_cast<int>((whole_value * multiplier) + decimal_value); static_cast<int>((whole_value * multiplier) + decimal_value);
if (*milli_token_ratio <= 0) { if (milli_token_ratio_ <= 0) {
error_list.push_back(GRPC_ERROR_CREATE( errors->AddError("must be greater than 0");
"field:retryThrottling field:tokenRatio error:value should "
"be greater than 0"));
}
} }
return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
} }
} // namespace //
// RetryMethodConfig
//
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> const JsonLoaderInterface* RetryMethodConfig::JsonLoader(const JsonArgs&) {
RetryServiceConfigParser::ParseGlobalParams(const ChannelArgs& /*args*/, static const auto* loader =
const Json& json) { JsonObjectLoader<RetryMethodConfig>()
auto it = json.object_value().find("retryThrottling"); // Note: The "retryableStatusCodes" field requires custom parsing,
if (it == json.object_value().end()) return nullptr; // so it's handled in JsonPostLoad() instead.
intptr_t max_milli_tokens = 0; .Field("maxAttempts", &RetryMethodConfig::max_attempts_)
intptr_t milli_token_ratio = 0; .Field("initialBackoff", &RetryMethodConfig::initial_backoff_)
grpc_error_handle error = .Field("maxBackoff", &RetryMethodConfig::max_backoff_)
ParseRetryThrottling(it->second, &max_milli_tokens, &milli_token_ratio); .Field("backoffMultiplier", &RetryMethodConfig::backoff_multiplier_)
if (!error.ok()) { .OptionalField("perAttemptRecvTimeout",
absl::Status status = absl::InvalidArgumentError(absl::StrCat( &RetryMethodConfig::per_attempt_recv_timeout_,
"error parsing retry global parameters: ", StatusToString(error))); GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING)
return status; .Finish();
} return loader;
return std::make_unique<RetryGlobalConfig>(max_milli_tokens,
milli_token_ratio);
} }
namespace { void RetryMethodConfig::JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors) {
grpc_error_handle ParseRetryPolicy( // Validate maxAttempts.
const ChannelArgs& args, const Json& json, int* max_attempts, {
Duration* initial_backoff, Duration* max_backoff, float* backoff_multiplier, ValidationErrors::ScopedField field(errors, ".maxAttempts");
StatusCodeSet* retryable_status_codes, if (!errors->FieldHasErrors()) {
absl::optional<Duration>* per_attempt_recv_timeout) { if (max_attempts_ <= 1) {
if (json.type() != Json::Type::OBJECT) { errors->AddError("must be at least 2");
return GRPC_ERROR_CREATE( } else if (max_attempts_ > MAX_MAX_RETRY_ATTEMPTS) {
"field:retryPolicy error:should be of type object");
}
std::vector<grpc_error_handle> error_list;
// Parse maxAttempts.
auto it = json.object_value().find("maxAttempts");
if (it == json.object_value().end()) {
error_list.push_back(
GRPC_ERROR_CREATE("field:maxAttempts error:required field missing"));
} else {
if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:maxAttempts error:should be of type number"));
} else {
*max_attempts =
gpr_parse_nonnegative_int(it->second.string_value().c_str());
if (*max_attempts <= 1) {
error_list.push_back(
GRPC_ERROR_CREATE("field:maxAttempts error:should be at least 2"));
} else if (*max_attempts > MAX_MAX_RETRY_ATTEMPTS) {
gpr_log(GPR_ERROR, gpr_log(GPR_ERROR,
"service config: clamped retryPolicy.maxAttempts at %d", "service config: clamped retryPolicy.maxAttempts at %d",
MAX_MAX_RETRY_ATTEMPTS); MAX_MAX_RETRY_ATTEMPTS);
*max_attempts = MAX_MAX_RETRY_ATTEMPTS; max_attempts_ = MAX_MAX_RETRY_ATTEMPTS;
} }
} }
} }
// Parse initialBackoff. // Validate initialBackoff.
if (ParseJsonObjectFieldAsDuration(json.object_value(), "initialBackoff", {
initial_backoff, &error_list) && ValidationErrors::ScopedField field(errors, ".initialBackoff");
*initial_backoff == Duration::Zero()) { if (!errors->FieldHasErrors() && initial_backoff_ == Duration::Zero()) {
error_list.push_back( errors->AddError("must be greater than 0");
GRPC_ERROR_CREATE("field:initialBackoff error:must be greater than 0"));
} }
// Parse maxBackoff.
if (ParseJsonObjectFieldAsDuration(json.object_value(), "maxBackoff",
max_backoff, &error_list) &&
*max_backoff == Duration::Zero()) {
error_list.push_back(
GRPC_ERROR_CREATE("field:maxBackoff error:must be greater than 0"));
} }
// Parse backoffMultiplier. // Validate maxBackoff.
it = json.object_value().find("backoffMultiplier"); {
if (it == json.object_value().end()) { ValidationErrors::ScopedField field(errors, ".maxBackoff");
error_list.push_back(GRPC_ERROR_CREATE( if (!errors->FieldHasErrors() && max_backoff_ == Duration::Zero()) {
"field:backoffMultiplier error:required field missing")); errors->AddError("must be greater than 0");
} else {
if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:backoffMultiplier error:should be of type number"));
} else {
if (sscanf(it->second.string_value().c_str(), "%f", backoff_multiplier) !=
1) {
error_list.push_back(
GRPC_ERROR_CREATE("field:backoffMultiplier error:failed to parse"));
} else if (*backoff_multiplier <= 0) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:backoffMultiplier error:must be greater than 0"));
} }
} }
// Validate backoffMultiplier.
{
ValidationErrors::ScopedField field(errors, ".backoffMultiplier");
if (!errors->FieldHasErrors() && backoff_multiplier_ <= 0) {
errors->AddError("must be greater than 0");
} }
// Parse retryableStatusCodes.
it = json.object_value().find("retryableStatusCodes");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryableStatusCodes error:must be of type array"));
} else {
for (const Json& element : it->second.array_value()) {
if (element.type() != Json::Type::STRING) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryableStatusCodes error:status codes should be of type "
"string"));
continue;
} }
// Parse retryableStatusCodes.
auto status_code_list = LoadJsonObjectField<std::vector<std::string>>(
json.object_value(), args, "retryableStatusCodes", errors,
/*required=*/false);
if (status_code_list.has_value()) {
for (size_t i = 0; i < status_code_list->size(); ++i) {
ValidationErrors::ScopedField field(
errors, absl::StrCat(".retryableStatusCodes[", i, "]"));
grpc_status_code status; grpc_status_code status;
if (!grpc_status_code_from_string(element.string_value().c_str(), if (!grpc_status_code_from_string((*status_code_list)[i].c_str(),
&status)) { &status)) {
error_list.push_back(GRPC_ERROR_CREATE( errors->AddError("failed to parse status code");
"field:retryableStatusCodes error:failed to parse status code")); } else {
continue; retryable_status_codes_.Add(status);
}
retryable_status_codes->Add(status);
} }
} }
} }
// Parse perAttemptRecvTimeout. // Validate perAttemptRecvTimeout.
if (args.GetBool(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING).value_or(false)) { if (args.IsEnabled(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING)) {
it = json.object_value().find("perAttemptRecvTimeout"); if (per_attempt_recv_timeout_.has_value()) {
if (it != json.object_value().end()) { ValidationErrors::ScopedField field(errors, ".perAttemptRecvTimeout");
Duration per_attempt_recv_timeout_value;
if (!ParseDurationFromJson(it->second, &per_attempt_recv_timeout_value)) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:perAttemptRecvTimeout error:type must be STRING of the "
"form given by google.proto.Duration."));
} else {
*per_attempt_recv_timeout = per_attempt_recv_timeout_value;
// TODO(roth): As part of implementing hedging, relax this check such // TODO(roth): As part of implementing hedging, relax this check such
// that we allow a value of 0 if a hedging policy is specified. // that we allow a value of 0 if a hedging policy is specified.
if (per_attempt_recv_timeout_value == Duration::Zero()) { if (!errors->FieldHasErrors() &&
error_list.push_back(GRPC_ERROR_CREATE( *per_attempt_recv_timeout_ == Duration::Zero()) {
"field:perAttemptRecvTimeout error:must be greater than 0")); errors->AddError("must be greater than 0");
}
} }
} else if (retryable_status_codes->Empty()) { } else if (retryable_status_codes_.Empty()) {
// If perAttemptRecvTimeout not present, retryableStatusCodes must be // If perAttemptRecvTimeout not present, retryableStatusCodes must be
// non-empty. // non-empty.
error_list.push_back(GRPC_ERROR_CREATE( ValidationErrors::ScopedField field(errors, ".retryableStatusCodes");
"field:retryableStatusCodes error:must be non-empty if " if (!errors->FieldHasErrors()) {
"perAttemptRecvTimeout not present")); errors->AddError(
"must be non-empty if perAttemptRecvTimeout not present");
} }
} else { }
} else if (retryable_status_codes_.Empty()) {
// Hedging not enabled, so the error message for // Hedging not enabled, so the error message for
// retryableStatusCodes unset should be different. // retryableStatusCodes unset should be different.
if (retryable_status_codes->Empty()) { ValidationErrors::ScopedField field(errors, ".retryableStatusCodes");
error_list.push_back(GRPC_ERROR_CREATE( if (!errors->FieldHasErrors()) {
"field:retryableStatusCodes error:must be non-empty")); errors->AddError("must be non-empty");
} }
} }
return GRPC_ERROR_CREATE_FROM_VECTOR("retryPolicy", &error_list);
} }
//
// RetryServiceConfigParser
//
size_t RetryServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
void RetryServiceConfigParser::Register(CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<RetryServiceConfigParser>());
}
namespace {
struct GlobalConfig {
std::unique_ptr<RetryGlobalConfig> retry_throttling;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<GlobalConfig>()
.OptionalField("retryThrottling", &GlobalConfig::retry_throttling)
.Finish();
return loader;
}
};
} // namespace
std::unique_ptr<ServiceConfigParser::ParsedConfig>
RetryServiceConfigParser::ParseGlobalParams(const ChannelArgs& /*args*/,
const Json& json,
ValidationErrors* errors) {
auto global_params = LoadFromJson<GlobalConfig>(json, JsonArgs(), errors);
return std::move(global_params.retry_throttling);
}
namespace {
struct MethodConfig {
std::unique_ptr<RetryMethodConfig> retry_policy;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<MethodConfig>()
.OptionalField("retryPolicy", &MethodConfig::retry_policy)
.Finish();
return loader;
}
};
} // namespace } // namespace
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig>
RetryServiceConfigParser::ParsePerMethodParams(const ChannelArgs& args, RetryServiceConfigParser::ParsePerMethodParams(const ChannelArgs& args,
const Json& json) { const Json& json,
// Parse retry policy. ValidationErrors* errors) {
auto it = json.object_value().find("retryPolicy"); auto method_params =
if (it == json.object_value().end()) return nullptr; LoadFromJson<MethodConfig>(json, JsonChannelArgs(args), errors);
int max_attempts = 0; return std::move(method_params.retry_policy);
Duration initial_backoff;
Duration max_backoff;
float backoff_multiplier = 0;
StatusCodeSet retryable_status_codes;
absl::optional<Duration> per_attempt_recv_timeout;
grpc_error_handle error = ParseRetryPolicy(
args, it->second, &max_attempts, &initial_backoff, &max_backoff,
&backoff_multiplier, &retryable_status_codes, &per_attempt_recv_timeout);
if (!error.ok()) {
absl::Status status = absl::InvalidArgumentError(absl::StrCat(
"error parsing retry method parameters: ", StatusToString(error)));
return status;
}
return std::make_unique<RetryMethodConfig>(
max_attempts, initial_backoff, max_backoff, backoff_multiplier,
retryable_status_codes, per_attempt_recv_timeout);
} }
} // namespace internal } // namespace internal

@ -24,7 +24,6 @@
#include <memory> #include <memory>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -32,7 +31,10 @@
#include "src/core/lib/channel/status_util.h" #include "src/core/lib/channel/status_util.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/time.h" #include "src/core/lib/gprpp/time.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
#include "src/core/lib/json/json_object_loader.h"
#include "src/core/lib/service_config/service_config_parser.h" #include "src/core/lib/service_config/service_config_parser.h"
namespace grpc_core { namespace grpc_core {
@ -40,31 +42,20 @@ namespace internal {
class RetryGlobalConfig : public ServiceConfigParser::ParsedConfig { class RetryGlobalConfig : public ServiceConfigParser::ParsedConfig {
public: public:
RetryGlobalConfig(intptr_t max_milli_tokens, intptr_t milli_token_ratio) uintptr_t max_milli_tokens() const { return max_milli_tokens_; }
: max_milli_tokens_(max_milli_tokens), uintptr_t milli_token_ratio() const { return milli_token_ratio_; }
milli_token_ratio_(milli_token_ratio) {}
intptr_t max_milli_tokens() const { return max_milli_tokens_; } static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
intptr_t milli_token_ratio() const { return milli_token_ratio_; } void JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors);
private: private:
intptr_t max_milli_tokens_ = 0; uintptr_t max_milli_tokens_ = 0;
intptr_t milli_token_ratio_ = 0; uintptr_t milli_token_ratio_ = 0;
}; };
class RetryMethodConfig : public ServiceConfigParser::ParsedConfig { class RetryMethodConfig : public ServiceConfigParser::ParsedConfig {
public: public:
RetryMethodConfig(int max_attempts, Duration initial_backoff,
Duration max_backoff, float backoff_multiplier,
StatusCodeSet retryable_status_codes,
absl::optional<Duration> per_attempt_recv_timeout)
: max_attempts_(max_attempts),
initial_backoff_(initial_backoff),
max_backoff_(max_backoff),
backoff_multiplier_(backoff_multiplier),
retryable_status_codes_(retryable_status_codes),
per_attempt_recv_timeout_(per_attempt_recv_timeout) {}
int max_attempts() const { return max_attempts_; } int max_attempts() const { return max_attempts_; }
Duration initial_backoff() const { return initial_backoff_; } Duration initial_backoff() const { return initial_backoff_; }
Duration max_backoff() const { return max_backoff_; } Duration max_backoff() const { return max_backoff_; }
@ -76,6 +67,10 @@ class RetryMethodConfig : public ServiceConfigParser::ParsedConfig {
return per_attempt_recv_timeout_; return per_attempt_recv_timeout_;
} }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
void JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors);
private: private:
int max_attempts_ = 0; int max_attempts_ = 0;
Duration initial_backoff_; Duration initial_backoff_;
@ -89,11 +84,13 @@ class RetryServiceConfigParser : public ServiceConfigParser::Parser {
public: public:
absl::string_view name() const override { return parser_name(); } absl::string_view name() const override { return parser_name(); }
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
ParseGlobalParams(const ChannelArgs& /*args*/, const Json& json) override; const ChannelArgs& /*args*/, const Json& json,
ValidationErrors* errors) override;
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
ParsePerMethodParams(const ChannelArgs& args, const Json& json) override; const ChannelArgs& args, const Json& json,
ValidationErrors* errors) override;
static size_t ParserIndex(); static size_t ParserIndex();
static void Register(CoreConfiguration::Builder* builder); static void Register(CoreConfiguration::Builder* builder);

@ -34,22 +34,22 @@ namespace internal {
// //
ServerRetryThrottleData::ServerRetryThrottleData( ServerRetryThrottleData::ServerRetryThrottleData(
intptr_t max_milli_tokens, intptr_t milli_token_ratio, uintptr_t max_milli_tokens, uintptr_t milli_token_ratio,
ServerRetryThrottleData* old_throttle_data) ServerRetryThrottleData* old_throttle_data)
: max_milli_tokens_(max_milli_tokens), : max_milli_tokens_(max_milli_tokens),
milli_token_ratio_(milli_token_ratio) { milli_token_ratio_(milli_token_ratio) {
intptr_t initial_milli_tokens = max_milli_tokens; uintptr_t initial_milli_tokens = max_milli_tokens;
// If there was a pre-existing entry for this server name, initialize // If there was a pre-existing entry for this server name, initialize
// the token count by scaling proportionately to the old data. This // the token count by scaling proportionately to the old data. This
// ensures that if we're already throttling retries on the old scale, // ensures that if we're already throttling retries on the old scale,
// we will start out doing the same thing on the new one. // we will start out doing the same thing on the new one.
if (old_throttle_data != nullptr) { if (old_throttle_data != nullptr) {
double token_fraction = double token_fraction =
static_cast<intptr_t>( static_cast<uintptr_t>(
gpr_atm_acq_load(&old_throttle_data->milli_tokens_)) / gpr_atm_acq_load(&old_throttle_data->milli_tokens_)) /
static_cast<double>(old_throttle_data->max_milli_tokens_); static_cast<double>(old_throttle_data->max_milli_tokens_);
initial_milli_tokens = initial_milli_tokens =
static_cast<intptr_t>(token_fraction * max_milli_tokens); static_cast<uintptr_t>(token_fraction * max_milli_tokens);
} }
gpr_atm_rel_store(&milli_tokens_, static_cast<gpr_atm>(initial_milli_tokens)); gpr_atm_rel_store(&milli_tokens_, static_cast<gpr_atm>(initial_milli_tokens));
// If there was a pre-existing entry, mark it as stale and give it a // If there was a pre-existing entry, mark it as stale and give it a
@ -86,8 +86,8 @@ bool ServerRetryThrottleData::RecordFailure() {
ServerRetryThrottleData* throttle_data = this; ServerRetryThrottleData* throttle_data = this;
GetReplacementThrottleDataIfNeeded(&throttle_data); GetReplacementThrottleDataIfNeeded(&throttle_data);
// We decrement milli_tokens by 1000 (1 token) for each failure. // We decrement milli_tokens by 1000 (1 token) for each failure.
const intptr_t new_value = const uintptr_t new_value =
static_cast<intptr_t>(gpr_atm_no_barrier_clamped_add( static_cast<uintptr_t>(gpr_atm_no_barrier_clamped_add(
&throttle_data->milli_tokens_, static_cast<gpr_atm>(-1000), &throttle_data->milli_tokens_, static_cast<gpr_atm>(-1000),
static_cast<gpr_atm>(0), static_cast<gpr_atm>(0),
static_cast<gpr_atm>(throttle_data->max_milli_tokens_))); static_cast<gpr_atm>(throttle_data->max_milli_tokens_)));
@ -118,8 +118,8 @@ ServerRetryThrottleMap* ServerRetryThrottleMap::Get() {
} }
RefCountedPtr<ServerRetryThrottleData> ServerRetryThrottleMap::GetDataForServer( RefCountedPtr<ServerRetryThrottleData> ServerRetryThrottleMap::GetDataForServer(
const std::string& server_name, intptr_t max_milli_tokens, const std::string& server_name, uintptr_t max_milli_tokens,
intptr_t milli_token_ratio) { uintptr_t milli_token_ratio) {
MutexLock lock(&mu_); MutexLock lock(&mu_);
auto it = map_.find(server_name); auto it = map_.find(server_name);
ServerRetryThrottleData* throttle_data = ServerRetryThrottleData* throttle_data =

@ -40,7 +40,8 @@ namespace internal {
/// Tracks retry throttling data for an individual server name. /// Tracks retry throttling data for an individual server name.
class ServerRetryThrottleData : public RefCounted<ServerRetryThrottleData> { class ServerRetryThrottleData : public RefCounted<ServerRetryThrottleData> {
public: public:
ServerRetryThrottleData(intptr_t max_milli_tokens, intptr_t milli_token_ratio, ServerRetryThrottleData(uintptr_t max_milli_tokens,
uintptr_t milli_token_ratio,
ServerRetryThrottleData* old_throttle_data); ServerRetryThrottleData* old_throttle_data);
~ServerRetryThrottleData() override; ~ServerRetryThrottleData() override;
@ -50,15 +51,15 @@ class ServerRetryThrottleData : public RefCounted<ServerRetryThrottleData> {
/// Records a success. /// Records a success.
void RecordSuccess(); void RecordSuccess();
intptr_t max_milli_tokens() const { return max_milli_tokens_; } uintptr_t max_milli_tokens() const { return max_milli_tokens_; }
intptr_t milli_token_ratio() const { return milli_token_ratio_; } uintptr_t milli_token_ratio() const { return milli_token_ratio_; }
private: private:
void GetReplacementThrottleDataIfNeeded( void GetReplacementThrottleDataIfNeeded(
ServerRetryThrottleData** throttle_data); ServerRetryThrottleData** throttle_data);
const intptr_t max_milli_tokens_; const uintptr_t max_milli_tokens_;
const intptr_t milli_token_ratio_; const uintptr_t milli_token_ratio_;
gpr_atm milli_tokens_; gpr_atm milli_tokens_;
// A pointer to the replacement for this ServerRetryThrottleData entry. // A pointer to the replacement for this ServerRetryThrottleData entry.
// If non-nullptr, then this entry is stale and must not be used. // If non-nullptr, then this entry is stale and must not be used.
@ -74,8 +75,8 @@ class ServerRetryThrottleMap {
/// Returns the failure data for \a server_name, creating a new entry if /// Returns the failure data for \a server_name, creating a new entry if
/// needed. /// needed.
RefCountedPtr<ServerRetryThrottleData> GetDataForServer( RefCountedPtr<ServerRetryThrottleData> GetDataForServer(
const std::string& server_name, intptr_t max_milli_tokens, const std::string& server_name, uintptr_t max_milli_tokens,
intptr_t milli_token_ratio); uintptr_t milli_token_ratio);
private: private:
using StringToDataMap = using StringToDataMap =

@ -35,7 +35,7 @@
#include <grpc/status.h> #include <grpc/status.h>
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include "src/core/ext/filters/fault_injection/service_config_parser.h" #include "src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h"
#include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/context.h" #include "src/core/lib/channel/context.h"
#include "src/core/lib/channel/status_util.h" #include "src/core/lib/channel/status_util.h"

@ -0,0 +1,118 @@
//
// Copyright 2021 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 <grpc/support/port_platform.h>
#include "src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h"
#include <vector>
#include "absl/types/optional.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h"
namespace grpc_core {
const JsonLoaderInterface*
FaultInjectionMethodParsedConfig::FaultInjectionPolicy::JsonLoader(
const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<FaultInjectionPolicy>()
.OptionalField("abortMessage", &FaultInjectionPolicy::abort_message)
.OptionalField("abortCodeHeader",
&FaultInjectionPolicy::abort_code_header)
.OptionalField("abortPercentageHeader",
&FaultInjectionPolicy::abort_percentage_header)
.OptionalField("abortPercentageNumerator",
&FaultInjectionPolicy::abort_percentage_numerator)
.OptionalField("abortPercentageDenominator",
&FaultInjectionPolicy::abort_percentage_denominator)
.OptionalField("delay", &FaultInjectionPolicy::delay)
.OptionalField("delayHeader", &FaultInjectionPolicy::delay_header)
.OptionalField("delayPercentageHeader",
&FaultInjectionPolicy::delay_percentage_header)
.OptionalField("delayPercentageNumerator",
&FaultInjectionPolicy::delay_percentage_numerator)
.OptionalField("delayPercentageDenominator",
&FaultInjectionPolicy::delay_percentage_denominator)
.OptionalField("maxFaults", &FaultInjectionPolicy::max_faults)
.Finish();
return loader;
}
void FaultInjectionMethodParsedConfig::FaultInjectionPolicy::JsonPostLoad(
const Json& json, const JsonArgs& args, ValidationErrors* errors) {
// Parse abort_code.
auto abort_code_string = LoadJsonObjectField<std::string>(
json.object_value(), args, "abortCode", errors, /*required=*/false);
if (abort_code_string.has_value() &&
!grpc_status_code_from_string(abort_code_string->c_str(), &abort_code)) {
ValidationErrors::ScopedField field(errors, ".abortCode");
errors->AddError("failed to parse status code");
}
// Validate abort_percentage_denominator.
if (abort_percentage_denominator != 100 &&
abort_percentage_denominator != 10000 &&
abort_percentage_denominator != 1000000) {
ValidationErrors::ScopedField field(errors, ".abortPercentageDenominator");
errors->AddError("must be one of 100, 10000, or 1000000");
}
// Validate delay_percentage_denominator.
if (delay_percentage_denominator != 100 &&
delay_percentage_denominator != 10000 &&
delay_percentage_denominator != 1000000) {
ValidationErrors::ScopedField field(errors, ".delayPercentageDenominator");
errors->AddError("must be one of 100, 10000, or 1000000");
}
}
const JsonLoaderInterface* FaultInjectionMethodParsedConfig::JsonLoader(
const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<FaultInjectionMethodParsedConfig>()
.OptionalField(
"faultInjectionPolicy",
&FaultInjectionMethodParsedConfig::fault_injection_policies_)
.Finish();
return loader;
}
std::unique_ptr<ServiceConfigParser::ParsedConfig>
FaultInjectionServiceConfigParser::ParsePerMethodParams(
const ChannelArgs& args, const Json& json, ValidationErrors* errors) {
// Only parse fault injection policy if the following channel arg is present.
if (!args.GetBool(GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG)
.value_or(false)) {
return nullptr;
}
// Parse fault injection policy from given Json
return LoadFromJson<std::unique_ptr<FaultInjectionMethodParsedConfig>>(
json, JsonArgs(), errors);
}
void FaultInjectionServiceConfigParser::Register(
CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<FaultInjectionServiceConfigParser>());
}
size_t FaultInjectionServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
} // namespace grpc_core

@ -14,8 +14,8 @@
// limitations under the License. // limitations under the License.
// //
#ifndef GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H #ifndef GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
#define GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H #define GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
@ -25,10 +25,8 @@
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include <grpc/status.h> #include <grpc/status.h>
@ -36,7 +34,10 @@
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/time.h" #include "src/core/lib/gprpp/time.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
#include "src/core/lib/json/json_object_loader.h"
#include "src/core/lib/service_config/service_config_parser.h" #include "src/core/lib/service_config/service_config_parser.h"
// Channel arg key for enabling parsing fault injection via method config. // Channel arg key for enabling parsing fault injection via method config.
@ -50,7 +51,7 @@ class FaultInjectionMethodParsedConfig
public: public:
struct FaultInjectionPolicy { struct FaultInjectionPolicy {
grpc_status_code abort_code = GRPC_STATUS_OK; grpc_status_code abort_code = GRPC_STATUS_OK;
std::string abort_message; std::string abort_message = "Fault injected";
std::string abort_code_header; std::string abort_code_header;
std::string abort_percentage_header; std::string abort_percentage_header;
uint32_t abort_percentage_numerator = 0; uint32_t abort_percentage_numerator = 0;
@ -64,11 +65,11 @@ class FaultInjectionMethodParsedConfig
// By default, the max allowed active faults are unlimited. // By default, the max allowed active faults are unlimited.
uint32_t max_faults = std::numeric_limits<uint32_t>::max(); uint32_t max_faults = std::numeric_limits<uint32_t>::max();
};
explicit FaultInjectionMethodParsedConfig( static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
std::vector<FaultInjectionPolicy> fault_injection_policies) void JsonPostLoad(const Json& json, const JsonArgs&,
: fault_injection_policies_(std::move(fault_injection_policies)) {} ValidationErrors* errors);
};
// Returns the fault injection policy at certain index. // Returns the fault injection policy at certain index.
// There might be multiple fault injection policies functioning at the same // There might be multiple fault injection policies functioning at the same
@ -83,6 +84,8 @@ class FaultInjectionMethodParsedConfig
return &fault_injection_policies_[index]; return &fault_injection_policies_[index];
} }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
private: private:
std::vector<FaultInjectionPolicy> fault_injection_policies_; std::vector<FaultInjectionPolicy> fault_injection_policies_;
}; };
@ -92,8 +95,9 @@ class FaultInjectionServiceConfigParser final
public: public:
absl::string_view name() const override { return parser_name(); } absl::string_view name() const override { return parser_name(); }
// Parses the per-method service config for fault injection filter. // Parses the per-method service config for fault injection filter.
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
ParsePerMethodParams(const ChannelArgs& args, const Json& json) override; const ChannelArgs& args, const Json& json,
ValidationErrors* errors) override;
// Returns the parser index for FaultInjectionServiceConfigParser. // Returns the parser index for FaultInjectionServiceConfigParser.
static size_t ParserIndex(); static size_t ParserIndex();
// Registers FaultInjectionServiceConfigParser to ServiceConfigParser. // Registers FaultInjectionServiceConfigParser to ServiceConfigParser.
@ -105,4 +109,4 @@ class FaultInjectionServiceConfigParser final
} // namespace grpc_core } // namespace grpc_core
#endif // GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H #endif // GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H

@ -1,185 +0,0 @@
//
// Copyright 2021 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 <grpc/support/port_platform.h>
#include "src/core/ext/filters/fault_injection/service_config_parser.h"
#include <algorithm>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/json/json_util.h"
namespace grpc_core {
namespace {
std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>
ParseFaultInjectionPolicy(const Json::Array& policies_json_array,
std::vector<grpc_error_handle>* error_list) {
std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy> policies;
for (size_t i = 0; i < policies_json_array.size(); i++) {
FaultInjectionMethodParsedConfig::FaultInjectionPolicy
fault_injection_policy;
std::vector<grpc_error_handle> sub_error_list;
if (policies_json_array[i].type() != Json::Type::OBJECT) {
error_list->push_back(GRPC_ERROR_CREATE(absl::StrCat(
"faultInjectionPolicy index ", i, " is not a JSON object")));
continue;
}
const Json::Object& json_object = policies_json_array[i].object_value();
// Parse abort_code
std::string abort_code_string;
if (ParseJsonObjectField(json_object, "abortCode", &abort_code_string,
&sub_error_list, false)) {
if (!grpc_status_code_from_string(abort_code_string.c_str(),
&(fault_injection_policy.abort_code))) {
sub_error_list.push_back(GRPC_ERROR_CREATE(
"field:abortCode error:failed to parse status code"));
}
}
// Parse abort_message
if (!ParseJsonObjectField(json_object, "abortMessage",
&fault_injection_policy.abort_message,
&sub_error_list, false)) {
fault_injection_policy.abort_message = "Fault injected";
}
// Parse abort_code_header
ParseJsonObjectField(json_object, "abortCodeHeader",
&fault_injection_policy.abort_code_header,
&sub_error_list, false);
// Parse abort_percentage_header
ParseJsonObjectField(json_object, "abortPercentageHeader",
&fault_injection_policy.abort_percentage_header,
&sub_error_list, false);
// Parse abort_percentage_numerator
ParseJsonObjectField(json_object, "abortPercentageNumerator",
&fault_injection_policy.abort_percentage_numerator,
&sub_error_list, false);
// Parse abort_percentage_denominator
if (ParseJsonObjectField(
json_object, "abortPercentageDenominator",
&fault_injection_policy.abort_percentage_denominator,
&sub_error_list, false)) {
if (fault_injection_policy.abort_percentage_denominator != 100 &&
fault_injection_policy.abort_percentage_denominator != 10000 &&
fault_injection_policy.abort_percentage_denominator != 1000000) {
sub_error_list.push_back(GRPC_ERROR_CREATE(
"field:abortPercentageDenominator error:Denominator can only be "
"one of "
"100, 10000, 1000000"));
}
}
// Parse delay
ParseJsonObjectFieldAsDuration(json_object, "delay",
&fault_injection_policy.delay,
&sub_error_list, false);
// Parse delay_header
ParseJsonObjectField(json_object, "delayHeader",
&fault_injection_policy.delay_header, &sub_error_list,
false);
// Parse delay_percentage_header
ParseJsonObjectField(json_object, "delayPercentageHeader",
&fault_injection_policy.delay_percentage_header,
&sub_error_list, false);
// Parse delay_percentage_numerator
ParseJsonObjectField(json_object, "delayPercentageNumerator",
&fault_injection_policy.delay_percentage_numerator,
&sub_error_list, false);
// Parse delay_percentage_denominator
if (ParseJsonObjectField(
json_object, "delayPercentageDenominator",
&fault_injection_policy.delay_percentage_denominator,
&sub_error_list, false)) {
if (fault_injection_policy.delay_percentage_denominator != 100 &&
fault_injection_policy.delay_percentage_denominator != 10000 &&
fault_injection_policy.delay_percentage_denominator != 1000000) {
sub_error_list.push_back(GRPC_ERROR_CREATE(
"field:delayPercentageDenominator error:Denominator can only be "
"one of "
"100, 10000, 1000000"));
}
}
// Parse max_faults
static_assert(
std::is_unsigned<decltype(fault_injection_policy.max_faults)>::value,
"maxFaults should be unsigned");
ParseJsonObjectField(json_object, "maxFaults",
&fault_injection_policy.max_faults, &sub_error_list,
false);
if (!sub_error_list.empty()) {
error_list->push_back(GRPC_ERROR_CREATE_FROM_VECTOR(
absl::StrCat("failed to parse faultInjectionPolicy index ", i),
&sub_error_list));
}
policies.push_back(std::move(fault_injection_policy));
}
return policies;
}
} // namespace
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
FaultInjectionServiceConfigParser::ParsePerMethodParams(const ChannelArgs& args,
const Json& json) {
// Only parse fault injection policy if the following channel arg is present.
if (!args.GetBool(GRPC_ARG_PARSE_FAULT_INJECTION_METHOD_CONFIG)
.value_or(false)) {
return nullptr;
}
// Parse fault injection policy from given Json
std::vector<FaultInjectionMethodParsedConfig::FaultInjectionPolicy>
fault_injection_policies;
std::vector<grpc_error_handle> error_list;
const Json::Array* policies_json_array;
if (ParseJsonObjectField(json.object_value(), "faultInjectionPolicy",
&policies_json_array, &error_list)) {
fault_injection_policies =
ParseFaultInjectionPolicy(*policies_json_array, &error_list);
}
if (!error_list.empty()) {
grpc_error_handle error =
GRPC_ERROR_CREATE_FROM_VECTOR("Fault injection parser", &error_list);
absl::Status status = absl::InvalidArgumentError(
absl::StrCat("error parsing fault injection method parameters: ",
StatusToString(error)));
return status;
}
if (fault_injection_policies.empty()) return nullptr;
return std::make_unique<FaultInjectionMethodParsedConfig>(
std::move(fault_injection_policies));
}
void FaultInjectionServiceConfigParser::Register(
CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<FaultInjectionServiceConfigParser>());
}
size_t FaultInjectionServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
} // namespace grpc_core

@ -20,9 +20,9 @@
#include "src/core/ext/filters/http/message_compress/message_decompress_filter.h" #include "src/core/ext/filters/http/message_compress/message_decompress_filter.h"
#include <stdint.h>
#include <string.h> #include <string.h>
#include <cstdint>
#include <new> #include <new>
#include "absl/status/status.h" #include "absl/status/status.h"
@ -57,13 +57,13 @@ class ChannelData {
message_size_service_config_parser_index_( message_size_service_config_parser_index_(
MessageSizeParser::ParserIndex()) {} MessageSizeParser::ParserIndex()) {}
int max_recv_size() const { return max_recv_size_; } absl::optional<uint32_t> max_recv_size() const { return max_recv_size_; }
size_t message_size_service_config_parser_index() const { size_t message_size_service_config_parser_index() const {
return message_size_service_config_parser_index_; return message_size_service_config_parser_index_;
} }
private: private:
int max_recv_size_; absl::optional<uint32_t> max_recv_size_;
const size_t message_size_service_config_parser_index_; const size_t message_size_service_config_parser_index_;
}; };
@ -86,10 +86,10 @@ class CallData {
const MessageSizeParsedConfig* limits = const MessageSizeParsedConfig* limits =
MessageSizeParsedConfig::GetFromCallContext( MessageSizeParsedConfig::GetFromCallContext(
args.context, chand->message_size_service_config_parser_index()); args.context, chand->message_size_service_config_parser_index());
if (limits != nullptr && limits->limits().max_recv_size >= 0 && if (limits != nullptr && limits->max_recv_size().has_value() &&
(limits->limits().max_recv_size < max_recv_message_length_ || (!max_recv_message_length_.has_value() ||
max_recv_message_length_ < 0)) { *limits->max_recv_size() < *max_recv_message_length_)) {
max_recv_message_length_ = limits->limits().max_recv_size; max_recv_message_length_ = *limits->max_recv_size();
} }
} }
@ -117,7 +117,7 @@ class CallData {
grpc_metadata_batch* recv_initial_metadata_ = nullptr; grpc_metadata_batch* recv_initial_metadata_ = nullptr;
// Fields for handling recv_message_ready callback // Fields for handling recv_message_ready callback
bool seen_recv_message_ready_ = false; bool seen_recv_message_ready_ = false;
int max_recv_message_length_; absl::optional<uint32_t> max_recv_message_length_;
grpc_compression_algorithm algorithm_ = GRPC_COMPRESS_NONE; grpc_compression_algorithm algorithm_ = GRPC_COMPRESS_NONE;
absl::optional<SliceBuffer>* recv_message_ = nullptr; absl::optional<SliceBuffer>* recv_message_ = nullptr;
uint32_t* recv_message_flags_ = nullptr; uint32_t* recv_message_flags_ = nullptr;
@ -171,15 +171,15 @@ void CallData::OnRecvMessageReady(void* arg, grpc_error_handle error) {
((*calld->recv_message_flags_ & GRPC_WRITE_INTERNAL_COMPRESS) == 0)) { ((*calld->recv_message_flags_ & GRPC_WRITE_INTERNAL_COMPRESS) == 0)) {
return calld->ContinueRecvMessageReadyCallback(absl::OkStatus()); return calld->ContinueRecvMessageReadyCallback(absl::OkStatus());
} }
if (calld->max_recv_message_length_ >= 0 && if (calld->max_recv_message_length_.has_value() &&
(*calld->recv_message_)->Length() > (*calld->recv_message_)->Length() >
static_cast<uint32_t>(calld->max_recv_message_length_)) { static_cast<uint32_t>(*calld->max_recv_message_length_)) {
GPR_DEBUG_ASSERT(calld->error_.ok()); GPR_DEBUG_ASSERT(calld->error_.ok());
calld->error_ = grpc_error_set_int( calld->error_ = grpc_error_set_int(
GRPC_ERROR_CREATE( GRPC_ERROR_CREATE(
absl::StrFormat("Received message larger than max (%u vs. %d)", absl::StrFormat("Received message larger than max (%u vs. %d)",
(*calld->recv_message_)->Length(), (*calld->recv_message_)->Length(),
calld->max_recv_message_length_)), *calld->max_recv_message_length_)),
StatusIntProperty::kRpcStatus, GRPC_STATUS_RESOURCE_EXHAUSTED); StatusIntProperty::kRpcStatus, GRPC_STATUS_RESOURCE_EXHAUSTED);
return calld->ContinueRecvMessageReadyCallback(calld->error_); return calld->ContinueRecvMessageReadyCallback(calld->error_);
} }

@ -18,17 +18,11 @@
#include "src/core/ext/filters/message_size/message_size_filter.h" #include "src/core/ext/filters/message_size/message_size_filter.h"
#include <algorithm> #include <cstdint>
#include <map>
#include <new> #include <new>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h" #include "absl/strings/str_format.h"
#include "absl/types/optional.h"
#include <grpc/impl/codegen/grpc_types.h> #include <grpc/impl/codegen/grpc_types.h>
#include <grpc/status.h> #include <grpc/status.h>
@ -38,7 +32,6 @@
#include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/channel_stack_builder.h" #include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/status_helper.h" #include "src/core/lib/gprpp/status_helper.h"
#include "src/core/lib/iomgr/call_combiner.h" #include "src/core/lib/iomgr/call_combiner.h"
@ -71,58 +64,54 @@ const MessageSizeParsedConfig* MessageSizeParsedConfig::GetFromCallContext(
svc_cfg_call_data->GetMethodParsedConfig(service_config_parser_index)); svc_cfg_call_data->GetMethodParsedConfig(service_config_parser_index));
} }
MessageSizeParsedConfig MessageSizeParsedConfig::GetFromChannelArgs(
const ChannelArgs& channel_args) {
MessageSizeParsedConfig limits;
limits.max_send_size_ = GetMaxSendSizeFromChannelArgs(channel_args);
limits.max_recv_size_ = GetMaxRecvSizeFromChannelArgs(channel_args);
return limits;
}
absl::optional<uint32_t> GetMaxRecvSizeFromChannelArgs(
const ChannelArgs& args) {
if (args.WantMinimalStack()) return absl::nullopt;
int size = args.GetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH)
.value_or(GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH);
if (size < 0) return absl::nullopt;
return static_cast<uint32_t>(size);
}
absl::optional<uint32_t> GetMaxSendSizeFromChannelArgs(
const ChannelArgs& args) {
if (args.WantMinimalStack()) return absl::nullopt;
int size = args.GetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH)
.value_or(GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH);
if (size < 0) return absl::nullopt;
return static_cast<uint32_t>(size);
}
const JsonLoaderInterface* MessageSizeParsedConfig::JsonLoader(
const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<MessageSizeParsedConfig>()
.OptionalField("maxRequestMessageBytes",
&MessageSizeParsedConfig::max_send_size_)
.OptionalField("maxResponseMessageBytes",
&MessageSizeParsedConfig::max_recv_size_)
.Finish();
return loader;
}
// //
// MessageSizeParser // MessageSizeParser
// //
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig>
MessageSizeParser::ParsePerMethodParams(const ChannelArgs& /*args*/, MessageSizeParser::ParsePerMethodParams(const ChannelArgs& /*args*/,
const Json& json) { const Json& json,
std::vector<grpc_error_handle> error_list; ValidationErrors* errors) {
// Max request size. return LoadFromJson<std::unique_ptr<MessageSizeParsedConfig>>(
int max_request_message_bytes = -1; json, JsonArgs(), errors);
auto it = json.object_value().find("maxRequestMessageBytes");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING &&
it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:maxRequestMessageBytes error:should be of type number"));
} else {
max_request_message_bytes =
gpr_parse_nonnegative_int(it->second.string_value().c_str());
if (max_request_message_bytes == -1) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:maxRequestMessageBytes error:should be non-negative"));
}
}
}
// Max response size.
int max_response_message_bytes = -1;
it = json.object_value().find("maxResponseMessageBytes");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::STRING &&
it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:maxResponseMessageBytes error:should be of type number"));
} else {
max_response_message_bytes =
gpr_parse_nonnegative_int(it->second.string_value().c_str());
if (max_response_message_bytes == -1) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:maxResponseMessageBytes error:should be non-negative"));
}
}
}
if (!error_list.empty()) {
grpc_error_handle error =
GRPC_ERROR_CREATE_FROM_VECTOR("Message size parser", &error_list);
absl::Status status = absl::InvalidArgumentError(
absl::StrCat("error parsing message size method parameters: ",
StatusToString(error)));
return status;
}
return std::make_unique<MessageSizeParsedConfig>(max_request_message_bytes,
max_response_message_bytes);
} }
void MessageSizeParser::Register(CoreConfiguration::Builder* builder) { void MessageSizeParser::Register(CoreConfiguration::Builder* builder) {
@ -135,23 +124,11 @@ size_t MessageSizeParser::ParserIndex() {
parser_name()); parser_name());
} }
int GetMaxRecvSizeFromChannelArgs(const ChannelArgs& args) {
if (args.WantMinimalStack()) return -1;
return std::max(-1, args.GetInt(GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH)
.value_or(GRPC_DEFAULT_MAX_RECV_MESSAGE_LENGTH));
}
int GetMaxSendSizeFromChannelArgs(const ChannelArgs& args) {
if (args.WantMinimalStack()) return -1;
return std::max(-1, args.GetInt(GRPC_ARG_MAX_SEND_MESSAGE_LENGTH)
.value_or(GRPC_DEFAULT_MAX_SEND_MESSAGE_LENGTH));
}
} // namespace grpc_core } // namespace grpc_core
namespace { namespace {
struct channel_data { struct channel_data {
grpc_core::MessageSizeParsedConfig::message_size_limits limits; grpc_core::MessageSizeParsedConfig limits;
const size_t service_config_parser_index{ const size_t service_config_parser_index{
grpc_core::MessageSizeParser::ParserIndex()}; grpc_core::MessageSizeParser::ParserIndex()};
}; };
@ -169,27 +146,30 @@ struct call_data {
// Note: Per-method config is only available on the client, so we // Note: Per-method config is only available on the client, so we
// apply the max request size to the send limit and the max response // apply the max request size to the send limit and the max response
// size to the receive limit. // size to the receive limit.
const grpc_core::MessageSizeParsedConfig* limits = const grpc_core::MessageSizeParsedConfig* config_from_call_context =
grpc_core::MessageSizeParsedConfig::GetFromCallContext( grpc_core::MessageSizeParsedConfig::GetFromCallContext(
args.context, chand.service_config_parser_index); args.context, chand.service_config_parser_index);
if (limits != nullptr) { if (config_from_call_context != nullptr) {
if (limits->limits().max_send_size >= 0 && absl::optional<uint32_t> max_send_size = limits.max_send_size();
(limits->limits().max_send_size < this->limits.max_send_size || absl::optional<uint32_t> max_recv_size = limits.max_recv_size();
this->limits.max_send_size < 0)) { if (config_from_call_context->max_send_size().has_value() &&
this->limits.max_send_size = limits->limits().max_send_size; (!max_send_size.has_value() ||
*config_from_call_context->max_send_size() < *max_send_size)) {
max_send_size = *config_from_call_context->max_send_size();
} }
if (limits->limits().max_recv_size >= 0 && if (config_from_call_context->max_recv_size().has_value() &&
(limits->limits().max_recv_size < this->limits.max_recv_size || (!max_recv_size.has_value() ||
this->limits.max_recv_size < 0)) { *config_from_call_context->max_recv_size() < *max_recv_size)) {
this->limits.max_recv_size = limits->limits().max_recv_size; max_recv_size = *config_from_call_context->max_recv_size();
} }
limits = grpc_core::MessageSizeParsedConfig(max_send_size, max_recv_size);
} }
} }
~call_data() {} ~call_data() {}
grpc_core::CallCombiner* call_combiner; grpc_core::CallCombiner* call_combiner;
grpc_core::MessageSizeParsedConfig::message_size_limits limits; grpc_core::MessageSizeParsedConfig limits;
// Receive closures are chained: we inject this closure as the // Receive closures are chained: we inject this closure as the
// recv_message_ready up-call on transport_stream_op, and remember to // recv_message_ready up-call on transport_stream_op, and remember to
// call our next_recv_message_ready member after handling it. // call our next_recv_message_ready member after handling it.
@ -214,13 +194,14 @@ struct call_data {
static void recv_message_ready(void* user_data, grpc_error_handle error) { static void recv_message_ready(void* user_data, grpc_error_handle error) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); grpc_call_element* elem = static_cast<grpc_call_element*>(user_data);
call_data* calld = static_cast<call_data*>(elem->call_data); call_data* calld = static_cast<call_data*>(elem->call_data);
if (calld->recv_message->has_value() && calld->limits.max_recv_size >= 0 && if (calld->recv_message->has_value() &&
calld->limits.max_recv_size().has_value() &&
(*calld->recv_message)->Length() > (*calld->recv_message)->Length() >
static_cast<size_t>(calld->limits.max_recv_size)) { static_cast<size_t>(*calld->limits.max_recv_size())) {
grpc_error_handle new_error = grpc_error_set_int( grpc_error_handle new_error = grpc_error_set_int(
GRPC_ERROR_CREATE(absl::StrFormat( GRPC_ERROR_CREATE(absl::StrFormat(
"Received message larger than max (%u vs. %d)", "Received message larger than max (%u vs. %d)",
(*calld->recv_message)->Length(), calld->limits.max_recv_size)), (*calld->recv_message)->Length(), *calld->limits.max_recv_size())),
grpc_core::StatusIntProperty::kRpcStatus, grpc_core::StatusIntProperty::kRpcStatus,
GRPC_STATUS_RESOURCE_EXHAUSTED); GRPC_STATUS_RESOURCE_EXHAUSTED);
error = grpc_error_add_child(error, new_error); error = grpc_error_add_child(error, new_error);
@ -269,15 +250,15 @@ static void message_size_start_transport_stream_op_batch(
grpc_call_element* elem, grpc_transport_stream_op_batch* op) { grpc_call_element* elem, grpc_transport_stream_op_batch* op) {
call_data* calld = static_cast<call_data*>(elem->call_data); call_data* calld = static_cast<call_data*>(elem->call_data);
// Check max send message size. // Check max send message size.
if (op->send_message && calld->limits.max_send_size >= 0 && if (op->send_message && calld->limits.max_send_size().has_value() &&
op->payload->send_message.send_message->Length() > op->payload->send_message.send_message->Length() >
static_cast<size_t>(calld->limits.max_send_size)) { static_cast<size_t>(*calld->limits.max_send_size())) {
grpc_transport_stream_op_batch_finish_with_failure( grpc_transport_stream_op_batch_finish_with_failure(
op, op,
grpc_error_set_int(GRPC_ERROR_CREATE(absl::StrFormat( grpc_error_set_int(GRPC_ERROR_CREATE(absl::StrFormat(
"Sent message larger than max (%u vs. %d)", "Sent message larger than max (%u vs. %d)",
op->payload->send_message.send_message->Length(), op->payload->send_message.send_message->Length(),
calld->limits.max_send_size)), *calld->limits.max_send_size())),
grpc_core::StatusIntProperty::kRpcStatus, grpc_core::StatusIntProperty::kRpcStatus,
GRPC_STATUS_RESOURCE_EXHAUSTED), GRPC_STATUS_RESOURCE_EXHAUSTED),
calld->call_combiner); calld->call_combiner);
@ -317,21 +298,13 @@ static void message_size_destroy_call_elem(
calld->~call_data(); calld->~call_data();
} }
grpc_core::MessageSizeParsedConfig::message_size_limits get_message_size_limits(
const grpc_core::ChannelArgs& channel_args) {
grpc_core::MessageSizeParsedConfig::message_size_limits lim;
lim.max_send_size = grpc_core::GetMaxSendSizeFromChannelArgs(channel_args);
lim.max_recv_size = grpc_core::GetMaxRecvSizeFromChannelArgs(channel_args);
return lim;
}
// Constructor for channel_data. // Constructor for channel_data.
static grpc_error_handle message_size_init_channel_elem( static grpc_error_handle message_size_init_channel_elem(
grpc_channel_element* elem, grpc_channel_element_args* args) { grpc_channel_element* elem, grpc_channel_element_args* args) {
GPR_ASSERT(!args->is_last); GPR_ASSERT(!args->is_last);
channel_data* chand = static_cast<channel_data*>(elem->channel_data); channel_data* chand = static_cast<channel_data*>(elem->channel_data);
new (chand) channel_data(); new (chand) channel_data();
chand->limits = get_message_size_limits( chand->limits = grpc_core::MessageSizeParsedConfig::GetFromChannelArgs(
grpc_core::ChannelArgs::FromC(args->channel_args)); grpc_core::ChannelArgs::FromC(args->channel_args));
return absl::OkStatus(); return absl::OkStatus();
} }
@ -375,10 +348,11 @@ static bool maybe_add_message_size_filter(
if (channel_args.WantMinimalStack()) { if (channel_args.WantMinimalStack()) {
return true; return true;
} }
grpc_core::MessageSizeParsedConfig::message_size_limits lim = grpc_core::MessageSizeParsedConfig limits =
get_message_size_limits(channel_args); grpc_core::MessageSizeParsedConfig::GetFromChannelArgs(channel_args);
const bool enable = const bool enable =
lim.max_send_size != -1 || lim.max_recv_size != -1 || limits.max_send_size().has_value() ||
limits.max_recv_size().has_value() ||
channel_args.GetString(GRPC_ARG_SERVICE_CONFIG).has_value(); channel_args.GetString(GRPC_ARG_SERVICE_CONFIG).has_value();
if (enable) builder->PrependFilter(&grpc_message_size_filter); if (enable) builder->PrependFilter(&grpc_message_size_filter);
return true; return true;

@ -20,18 +20,22 @@
#include <grpc/support/port_platform.h> #include <grpc/support/port_platform.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <memory> #include <memory>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_fwd.h" #include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/context.h" #include "src/core/lib/channel/context.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
#include "src/core/lib/json/json_object_loader.h"
#include "src/core/lib/service_config/service_config_parser.h" #include "src/core/lib/service_config/service_config_parser.h"
extern const grpc_channel_filter grpc_message_size_filter; extern const grpc_channel_filter grpc_message_size_filter;
@ -40,32 +44,35 @@ namespace grpc_core {
class MessageSizeParsedConfig : public ServiceConfigParser::ParsedConfig { class MessageSizeParsedConfig : public ServiceConfigParser::ParsedConfig {
public: public:
struct message_size_limits { absl::optional<uint32_t> max_send_size() const { return max_send_size_; }
int max_send_size; absl::optional<uint32_t> max_recv_size() const { return max_recv_size_; }
int max_recv_size;
};
MessageSizeParsedConfig(int max_send_size, int max_recv_size) { MessageSizeParsedConfig() = default;
limits_.max_send_size = max_send_size;
limits_.max_recv_size = max_recv_size;
}
const message_size_limits& limits() const { return limits_; } MessageSizeParsedConfig(absl::optional<uint32_t> max_send_size,
absl::optional<uint32_t> max_recv_size)
: max_send_size_(max_send_size), max_recv_size_(max_recv_size) {}
static const MessageSizeParsedConfig* GetFromCallContext( static const MessageSizeParsedConfig* GetFromCallContext(
const grpc_call_context_element* context, const grpc_call_context_element* context,
size_t service_config_parser_index); size_t service_config_parser_index);
static MessageSizeParsedConfig GetFromChannelArgs(const ChannelArgs& args);
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
private: private:
message_size_limits limits_; absl::optional<uint32_t> max_send_size_;
absl::optional<uint32_t> max_recv_size_;
}; };
class MessageSizeParser : public ServiceConfigParser::Parser { class MessageSizeParser : public ServiceConfigParser::Parser {
public: public:
absl::string_view name() const override { return parser_name(); } absl::string_view name() const override { return parser_name(); }
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
ParsePerMethodParams(const ChannelArgs& /*args*/, const Json& json) override; const ChannelArgs& /*args*/, const Json& json,
ValidationErrors* errors) override;
static void Register(CoreConfiguration::Builder* builder); static void Register(CoreConfiguration::Builder* builder);
@ -75,8 +82,8 @@ class MessageSizeParser : public ServiceConfigParser::Parser {
static absl::string_view parser_name() { return "message_size"; } static absl::string_view parser_name() { return "message_size"; }
}; };
int GetMaxRecvSizeFromChannelArgs(const ChannelArgs& args); absl::optional<uint32_t> GetMaxRecvSizeFromChannelArgs(const ChannelArgs& args);
int GetMaxSendSizeFromChannelArgs(const ChannelArgs& args); absl::optional<uint32_t> GetMaxSendSizeFromChannelArgs(const ChannelArgs& args);
} // namespace grpc_core } // namespace grpc_core

File diff suppressed because it is too large Load Diff

@ -26,11 +26,11 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/security/authorization/grpc_authorization_engine.h" #include "src/core/lib/security/authorization/grpc_authorization_engine.h"
#include "src/core/lib/security/authorization/rbac_policy.h" #include "src/core/lib/security/authorization/rbac_policy.h"
@ -69,8 +69,9 @@ class RbacServiceConfigParser : public ServiceConfigParser::Parser {
public: public:
absl::string_view name() const override { return parser_name(); } absl::string_view name() const override { return parser_name(); }
// Parses the per-method service config for rbac filter. // Parses the per-method service config for rbac filter.
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>> std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
ParsePerMethodParams(const ChannelArgs& args, const Json& json) override; const ChannelArgs& args, const Json& json,
ValidationErrors* errors) override;
// Returns the parser index for RbacServiceConfigParser. // Returns the parser index for RbacServiceConfigParser.
static size_t ParserIndex(); static size_t ParserIndex();
// Registers RbacServiceConfigParser to ServiceConfigParser. // Registers RbacServiceConfigParser to ServiceConfigParser.

@ -38,7 +38,7 @@
#include <grpc/status.h> #include <grpc/status.h>
#include "src/core/ext/filters/fault_injection/fault_injection_filter.h" #include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
#include "src/core/ext/filters/fault_injection/service_config_parser.h" #include "src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h"
#include "src/core/ext/xds/xds_common_types.h" #include "src/core/ext/xds/xds_common_types.h"
#include "src/core/ext/xds/xds_http_filters.h" #include "src/core/ext/xds/xds_http_filters.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"

@ -165,10 +165,6 @@ Json ParsePathMatcherToJson(const envoy_type_matcher_v3_PathMatcher* matcher,
return Json::Object{{"path", std::move(path_json)}}; return Json::Object{{"path", std::move(path_json)}};
} }
Json ParseUInt32ValueToJson(const google_protobuf_UInt32Value* value) {
return Json::Object{{"value", google_protobuf_UInt32Value_value(value)}};
}
Json ParseCidrRangeToJson(const envoy_config_core_v3_CidrRange* range) { Json ParseCidrRangeToJson(const envoy_config_core_v3_CidrRange* range) {
Json::Object json; Json::Object json;
json.emplace("addressPrefix", json.emplace("addressPrefix",
@ -176,7 +172,7 @@ Json ParseCidrRangeToJson(const envoy_config_core_v3_CidrRange* range) {
envoy_config_core_v3_CidrRange_address_prefix(range))); envoy_config_core_v3_CidrRange_address_prefix(range)));
const auto* prefix_len = envoy_config_core_v3_CidrRange_prefix_len(range); const auto* prefix_len = envoy_config_core_v3_CidrRange_prefix_len(range);
if (prefix_len != nullptr) { if (prefix_len != nullptr) {
json.emplace("prefixLen", ParseUInt32ValueToJson(prefix_len)); json.emplace("prefixLen", google_protobuf_UInt32Value_value(prefix_len));
} }
return json; return json;
} }

@ -20,6 +20,7 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -392,6 +393,26 @@ class AutoLoader<absl::optional<T>> final : public LoadOptional {
~AutoLoader() = default; ~AutoLoader() = default;
}; };
// Specializations of AutoLoader for std::unique_ptr<>.
template <typename T>
class AutoLoader<std::unique_ptr<T>> final : public LoadOptional {
public:
void* Emplace(void* dst) const final {
auto& p = *static_cast<std::unique_ptr<T>*>(dst);
p = std::make_unique<T>();
return p.get();
}
void Reset(void* dst) const final {
static_cast<std::unique_ptr<T>*>(dst)->reset();
}
const LoaderInterface* ElementLoader() const final {
return LoaderForType<T>();
}
private:
~AutoLoader() = default;
};
// Implementation of aforementioned LoaderForType. // Implementation of aforementioned LoaderForType.
// Simply keeps a static AutoLoader<T> and returns a pointer to that. // Simply keeps a static AutoLoader<T> and returns a pointer to that.
template <typename T> template <typename T>

@ -58,7 +58,7 @@
namespace grpc_core { namespace grpc_core {
// TODO(roth): Consider stripping this down further to the completely minimal // TODO(roth): Consider stripping this down further to the completely minimal
// interface requied to be exposed as part of the resolver API. // interface required to be exposed as part of the resolver API.
class ServiceConfig : public RefCounted<ServiceConfig> { class ServiceConfig : public RefCounted<ServiceConfig> {
public: public:
static absl::string_view ChannelArgName() { static absl::string_view ChannelArgName() {

@ -20,113 +20,134 @@
#include <string.h> #include <string.h>
#include <map>
#include <string> #include <string>
#include <utility> #include <utility>
#include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h" #include "absl/types/optional.h"
#include <grpc/support/log.h>
#include "src/core/lib/config/core_configuration.h" #include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/memory.h" #include "src/core/lib/gprpp/memory.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
#include "src/core/lib/json/json_object_loader.h"
#include "src/core/lib/service_config/service_config_parser.h" #include "src/core/lib/service_config/service_config_parser.h"
#include "src/core/lib/slice/slice.h" #include "src/core/lib/slice/slice.h"
#include "src/core/lib/slice/slice_internal.h" #include "src/core/lib/slice/slice_internal.h"
namespace grpc_core { namespace grpc_core {
absl::StatusOr<RefCountedPtr<ServiceConfig>> ServiceConfigImpl::Create( namespace {
const ChannelArgs& args, absl::string_view json_string) {
auto json = Json::Parse(json_string); struct MethodConfig {
if (!json.ok()) return json.status(); struct Name {
absl::Status status; absl::optional<std::string> service;
auto service_config = MakeRefCounted<ServiceConfigImpl>( absl::optional<std::string> method;
args, std::string(json_string), std::move(*json), &status);
if (!status.ok()) return status; static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
return service_config; static const auto* loader = JsonObjectLoader<Name>()
.OptionalField("service", &Name::service)
.OptionalField("method", &Name::method)
.Finish();
return loader;
} }
ServiceConfigImpl::ServiceConfigImpl(const ChannelArgs& args, void JsonPostLoad(const Json&, const JsonArgs&, ValidationErrors* errors) {
std::string json_string, Json json, if (!service.has_value() && method.has_value()) {
absl::Status* status) errors->AddError("method name populated without service name");
: json_string_(std::move(json_string)), json_(std::move(json)) {
GPR_DEBUG_ASSERT(status != nullptr);
if (json_.type() != Json::Type::OBJECT) {
*status = absl::InvalidArgumentError("JSON value is not an object");
return;
} }
std::vector<std::string> errors;
auto parsed_global_configs =
CoreConfiguration::Get().service_config_parser().ParseGlobalParameters(
args, json_);
if (!parsed_global_configs.ok()) {
errors.emplace_back(parsed_global_configs.status().message());
} else {
parsed_global_configs_ = std::move(*parsed_global_configs);
} }
absl::Status local_status = ParsePerMethodParams(args);
if (!local_status.ok()) errors.emplace_back(local_status.message()); std::string Path() const {
if (!errors.empty()) { if (!service.has_value() || service->empty()) return "";
*status = absl::InvalidArgumentError(absl::StrCat( return absl::StrCat("/", *service, "/",
"Service config parsing errors: [", absl::StrJoin(errors, "; "), "]")); method.has_value() ? *method : "");
} }
};
std::vector<Name> names;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = JsonObjectLoader<MethodConfig>()
.OptionalField("name", &MethodConfig::names)
.Finish();
return loader;
} }
};
ServiceConfigImpl::~ServiceConfigImpl() { } // namespace
for (auto& p : parsed_method_configs_map_) {
CSliceUnref(p.first); absl::StatusOr<RefCountedPtr<ServiceConfig>> ServiceConfigImpl::Create(
const ChannelArgs& args, absl::string_view json_string) {
auto json = Json::Parse(json_string);
if (!json.ok()) return json.status();
ValidationErrors errors;
auto service_config = Create(args, *json, json_string, &errors);
if (!errors.ok()) return errors.status("errors validating service config");
return service_config;
} }
RefCountedPtr<ServiceConfig> ServiceConfigImpl::Create(
const ChannelArgs& args, const Json& json, ValidationErrors* errors) {
return Create(args, json, json.Dump(), errors);
} }
absl::Status ServiceConfigImpl::ParseJsonMethodConfig(const ChannelArgs& args, RefCountedPtr<ServiceConfig> ServiceConfigImpl::Create(
const Json& json, const ChannelArgs& args, const Json& json, absl::string_view json_string,
size_t index) { ValidationErrors* errors) {
std::vector<std::string> errors; if (json.type() != Json::Type::OBJECT) {
const ServiceConfigParser::ParsedConfigVector* vector_ptr = nullptr; errors->AddError("is not an object");
// Parse method config with each registered parser. return nullptr;
auto parsed_configs_or =
CoreConfiguration::Get().service_config_parser().ParsePerMethodParameters(
args, json);
if (!parsed_configs_or.ok()) {
errors.emplace_back(parsed_configs_or.status().message());
} else {
auto parsed_configs =
std::make_unique<ServiceConfigParser::ParsedConfigVector>(
std::move(*parsed_configs_or));
parsed_method_config_vectors_storage_.push_back(std::move(parsed_configs));
vector_ptr = parsed_method_config_vectors_storage_.back().get();
}
// Add an entry for each path.
auto it = json.object_value().find("name");
if (it != json.object_value().end()) {
if (it->second.type() != Json::Type::ARRAY) {
errors.emplace_back("field:name error:not of type Array");
} else {
const Json::Array& name_array = it->second.array_value();
for (const Json& name : name_array) {
absl::StatusOr<std::string> path = ParseJsonMethodName(name);
if (!path.ok()) {
errors.emplace_back(path.status().message());
} else {
if (path->empty()) {
if (default_method_config_vector_ != nullptr) {
errors.emplace_back(
"field:name error:multiple default method configs");
} }
default_method_config_vector_ = vector_ptr; auto service_config = MakeRefCounted<ServiceConfigImpl>();
service_config->json_string_ = std::string(json_string);
// Parse global parameters.
service_config->parsed_global_configs_ =
CoreConfiguration::Get().service_config_parser().ParseGlobalParameters(
args, json, errors);
// Parse per-method parameters.
auto method_configs = LoadJsonObjectField<std::vector<Json::Object>>(
json.object_value(), JsonArgs(), "methodConfig", errors,
/*required=*/false);
if (method_configs.has_value()) {
service_config->parsed_method_config_vectors_storage_.reserve(
method_configs->size());
for (size_t i = 0; i < method_configs->size(); ++i) {
const Json::Object& method_config_json = (*method_configs)[i];
ValidationErrors::ScopedField field(
errors, absl::StrCat(".methodConfig[", i, "]"));
// Have each parser read this method config.
auto parsed_configs =
CoreConfiguration::Get()
.service_config_parser()
.ParsePerMethodParameters(args, method_config_json, errors);
// Store the parsed configs.
service_config->parsed_method_config_vectors_storage_.push_back(
std::move(parsed_configs));
const ServiceConfigParser::ParsedConfigVector* vector_ptr =
&service_config->parsed_method_config_vectors_storage_.back();
// Parse the names.
auto method_config =
LoadFromJson<MethodConfig>(method_config_json, JsonArgs(), errors);
for (size_t j = 0; j < method_config.names.size(); ++j) {
ValidationErrors::ScopedField field(errors,
absl::StrCat(".name[", j, "]"));
std::string path = method_config.names[j].Path();
if (path.empty()) {
if (service_config->default_method_config_vector_ != nullptr) {
errors->AddError("duplicate default method config");
}
service_config->default_method_config_vector_ = vector_ptr;
} else { } else {
grpc_slice key = grpc_slice_from_cpp_string(std::move(*path)); grpc_slice key = grpc_slice_from_cpp_string(std::move(path));
// If the key is not already present in the map, this will // If the key is not already present in the map, this will
// store a ref to the key in the map. // store a ref to the key in the map.
auto& value = parsed_method_configs_map_[key]; auto& value = service_config->parsed_method_configs_map_[key];
if (value != nullptr) { if (value != nullptr) {
errors.emplace_back( errors->AddError(absl::StrCat("multiple method configs for path ",
"field:name error:multiple method configs with same name"); StringViewFromSlice(key)));
// The map entry already existed, so we need to unref the // The map entry already existed, so we need to unref the
// key we just created. // key we just created.
CSliceUnref(key); CSliceUnref(key);
@ -137,80 +158,13 @@ absl::Status ServiceConfigImpl::ParseJsonMethodConfig(const ChannelArgs& args,
} }
} }
} }
} return service_config;
if (!errors.empty()) {
return absl::InvalidArgumentError(
absl::StrCat("index ", index, ": [", absl::StrJoin(errors, "; "), "]"));
}
return absl::OkStatus();
} }
absl::Status ServiceConfigImpl::ParsePerMethodParams(const ChannelArgs& args) { ServiceConfigImpl::~ServiceConfigImpl() {
auto it = json_.object_value().find("methodConfig"); for (auto& p : parsed_method_configs_map_) {
if (it == json_.object_value().end()) return absl::OkStatus(); CSliceUnref(p.first);
if (it->second.type() != Json::Type::ARRAY) {
return absl::InvalidArgumentError("field must be of type array");
}
std::vector<std::string> errors;
for (size_t i = 0; i < it->second.array_value().size(); ++i) {
const Json& method_config = it->second.array_value()[i];
if (method_config.type() != Json::Type::OBJECT) {
errors.emplace_back(absl::StrCat("index ", i, ": not of type Object"));
} else {
absl::Status status = ParseJsonMethodConfig(args, method_config, i);
if (!status.ok()) errors.emplace_back(status.message());
}
}
if (!errors.empty()) {
return absl::InvalidArgumentError(absl::StrCat(
"errors parsing methodConfig: [", absl::StrJoin(errors, "; "), "]"));
}
return absl::OkStatus();
} }
absl::StatusOr<std::string> ServiceConfigImpl::ParseJsonMethodName(
const Json& json) {
if (json.type() != Json::Type::OBJECT) {
return absl::InvalidArgumentError("field:name error:type is not object");
}
// Find service name.
const std::string* service_name = nullptr;
auto it = json.object_value().find("service");
if (it != json.object_value().end() &&
it->second.type() != Json::Type::JSON_NULL) {
if (it->second.type() != Json::Type::STRING) {
return absl::InvalidArgumentError(
"field:name error: field:service error:not of type string");
}
if (!it->second.string_value().empty()) {
service_name = &it->second.string_value();
}
}
const std::string* method_name = nullptr;
// Find method name.
it = json.object_value().find("method");
if (it != json.object_value().end() &&
it->second.type() != Json::Type::JSON_NULL) {
if (it->second.type() != Json::Type::STRING) {
return absl::InvalidArgumentError(
"field:name error: field:method error:not of type string");
}
if (!it->second.string_value().empty()) {
method_name = &it->second.string_value();
}
}
// 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) {
return absl::InvalidArgumentError(
"field:name error:method name populated without service name");
}
return "";
}
// Construct path.
return absl::StrCat("/", *service_name, "/",
method_name == nullptr ? "" : *method_name);
} }
const ServiceConfigParser::ParsedConfigVector* const ServiceConfigParser::ParsedConfigVector*

@ -26,7 +26,6 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
@ -35,6 +34,7 @@
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
#include "src/core/lib/service_config/service_config.h" #include "src/core/lib/service_config/service_config.h"
#include "src/core/lib/service_config/service_config_parser.h" #include "src/core/lib/service_config/service_config_parser.h"
@ -72,8 +72,15 @@ class ServiceConfigImpl final : public ServiceConfig {
static absl::StatusOr<RefCountedPtr<ServiceConfig>> Create( static absl::StatusOr<RefCountedPtr<ServiceConfig>> Create(
const ChannelArgs& args, absl::string_view json_string); const ChannelArgs& args, absl::string_view json_string);
ServiceConfigImpl(const ChannelArgs& args, std::string json_string, Json json, // Alternate forms that are useful in edge cases.
absl::Status* status); static RefCountedPtr<ServiceConfig> Create(const ChannelArgs& args,
const Json& json,
absl::string_view json_string,
ValidationErrors* errors);
static RefCountedPtr<ServiceConfig> Create(const ChannelArgs& args,
const Json& json,
ValidationErrors* errors);
~ServiceConfigImpl() override; ~ServiceConfigImpl() override;
absl::string_view json_string() const override { return json_string_; } absl::string_view json_string() const override { return json_string_; }
@ -94,20 +101,10 @@ class ServiceConfigImpl final : public ServiceConfig {
const grpc_slice& path) const override; const grpc_slice& path) const override;
private: private:
// Helper functions for parsing the method configs.
absl::Status ParsePerMethodParams(const ChannelArgs& args);
absl::Status ParseJsonMethodConfig(const ChannelArgs& args, const Json& json,
size_t index);
// Returns a path string for the JSON name object specified by json.
// Sets *error on error.
static absl::StatusOr<std::string> ParseJsonMethodName(const Json& json);
std::string json_string_; std::string json_string_;
Json json_; Json json_;
std::vector<std::unique_ptr<ServiceConfigParser::ParsedConfig>> ServiceConfigParser::ParsedConfigVector parsed_global_configs_;
parsed_global_configs_;
// 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.
@ -118,11 +115,11 @@ class ServiceConfigImpl final : public ServiceConfig {
const ServiceConfigParser::ParsedConfigVector* default_method_config_vector_ = const ServiceConfigParser::ParsedConfigVector* default_method_config_vector_ =
nullptr; 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_map_ and default_method_config_vector_.
std::vector<std::unique_ptr<ServiceConfigParser::ParsedConfigVector>> std::vector<ServiceConfigParser::ParsedConfigVector>
parsed_method_config_vectors_storage_; parsed_method_config_vectors_storage_;
}; };
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_LIB_SERVICE_CONFIG_SERVICE_CONFIG_IMPL_H */ #endif // GRPC_CORE_LIB_SERVICE_CONFIG_SERVICE_CONFIG_IMPL_H

@ -22,9 +22,7 @@
#include <string> #include <string>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include <grpc/support/log.h> #include <grpc/support/log.h>
@ -49,43 +47,28 @@ void ServiceConfigParser::Builder::RegisterParser(
registered_parsers_.emplace_back(std::move(parser)); registered_parsers_.emplace_back(std::move(parser));
} }
absl::StatusOr<ServiceConfigParser::ParsedConfigVector> ServiceConfigParser::ParsedConfigVector
ServiceConfigParser::ParseGlobalParameters(const ChannelArgs& args, ServiceConfigParser::ParseGlobalParameters(const ChannelArgs& args,
const Json& json) const { const Json& json,
ValidationErrors* errors) const {
ParsedConfigVector parsed_global_configs; ParsedConfigVector parsed_global_configs;
std::vector<std::string> errors; for (auto& parser : registered_parsers_) {
for (size_t i = 0; i < registered_parsers_.size(); i++) { parsed_global_configs.push_back(
auto parsed_config = registered_parsers_[i]->ParseGlobalParams(args, json); parser->ParseGlobalParams(args, json, errors));
if (!parsed_config.ok()) {
errors.emplace_back(parsed_config.status().message());
} else {
parsed_global_configs.push_back(std::move(*parsed_config));
} }
} return parsed_global_configs;
if (!errors.empty()) {
return absl::InvalidArgumentError(absl::StrJoin(errors, "; "));
}
return std::move(parsed_global_configs);
} }
absl::StatusOr<ServiceConfigParser::ParsedConfigVector> ServiceConfigParser::ParsedConfigVector
ServiceConfigParser::ParsePerMethodParameters(const ChannelArgs& args, ServiceConfigParser::ParsePerMethodParameters(const ChannelArgs& args,
const Json& json) const { const Json& json,
ValidationErrors* errors) const {
ParsedConfigVector parsed_method_configs; ParsedConfigVector parsed_method_configs;
std::vector<std::string> errors; for (auto& parser : registered_parsers_) {
for (size_t i = 0; i < registered_parsers_.size(); ++i) { parsed_method_configs.push_back(
auto parsed_config = parser->ParsePerMethodParams(args, json, errors));
registered_parsers_[i]->ParsePerMethodParams(args, json);
if (!parsed_config.ok()) {
errors.emplace_back(parsed_config.status().message());
} else {
parsed_method_configs.push_back(std::move(*parsed_config));
}
}
if (!errors.empty()) {
return absl::InvalidArgumentError(absl::StrJoin(errors, "; "));
} }
return std::move(parsed_method_configs); return parsed_method_configs;
} }
size_t ServiceConfigParser::GetParserIndex(absl::string_view name) const { size_t ServiceConfigParser::GetParserIndex(absl::string_view name) const {

@ -26,10 +26,10 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h" #include "src/core/lib/json/json.h"
namespace grpc_core { namespace grpc_core {
@ -52,13 +52,15 @@ class ServiceConfigParser {
virtual absl::string_view name() const = 0; virtual absl::string_view name() const = 0;
virtual absl::StatusOr<std::unique_ptr<ParsedConfig>> ParseGlobalParams( virtual std::unique_ptr<ParsedConfig> ParseGlobalParams(
const ChannelArgs& /*args*/, const Json& /*json*/) { const ChannelArgs& /*args*/, const Json& /*json*/,
ValidationErrors* /*errors*/) {
return nullptr; return nullptr;
} }
virtual absl::StatusOr<std::unique_ptr<ParsedConfig>> ParsePerMethodParams( virtual std::unique_ptr<ParsedConfig> ParsePerMethodParams(
const ChannelArgs& /*args*/, const Json& /*json*/) { const ChannelArgs& /*args*/, const Json& /*json*/,
ValidationErrors* /*errors*/) {
return nullptr; return nullptr;
} }
}; };
@ -80,11 +82,13 @@ class ServiceConfigParser {
ServiceConfigParserList registered_parsers_; ServiceConfigParserList registered_parsers_;
}; };
absl::StatusOr<ParsedConfigVector> ParseGlobalParameters( ParsedConfigVector ParseGlobalParameters(const ChannelArgs& args,
const ChannelArgs& args, const Json& json) const; const Json& json,
ValidationErrors* errors) const;
absl::StatusOr<ParsedConfigVector> ParsePerMethodParameters( ParsedConfigVector ParsePerMethodParameters(const ChannelArgs& args,
const ChannelArgs& args, const Json& json) const; const Json& json,
ValidationErrors* errors) const;
// Return the index for a given registered parser. // Return the index for a given registered parser.
// If there is an error, return -1. // If there is an error, return -1.
@ -98,4 +102,4 @@ class ServiceConfigParser {
} // namespace grpc_core } // namespace grpc_core
#endif /* GRPC_CORE_LIB_SERVICE_CONFIG_SERVICE_CONFIG_PARSER_H */ #endif // GRPC_CORE_LIB_SERVICE_CONFIG_SERVICE_CONFIG_PARSER_H

@ -25,6 +25,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/client_channel_channelz.cc', 'src/core/ext/filters/client_channel/client_channel_channelz.cc',
'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc',
'src/core/ext/filters/client_channel/client_channel_plugin.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc',
'src/core/ext/filters/client_channel/client_channel_service_config.cc',
'src/core/ext/filters/client_channel/config_selector.cc', 'src/core/ext/filters/client_channel/config_selector.cc',
'src/core/ext/filters/client_channel/dynamic_filters.cc', 'src/core/ext/filters/client_channel/dynamic_filters.cc',
'src/core/ext/filters/client_channel/global_subchannel_pool.cc', 'src/core/ext/filters/client_channel/global_subchannel_pool.cc',
@ -66,7 +67,6 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/resolver/polling_resolver.cc', 'src/core/ext/filters/client_channel/resolver/polling_resolver.cc',
'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc',
'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc',
'src/core/ext/filters/client_channel/resolver_result_parsing.cc',
'src/core/ext/filters/client_channel/retry_filter.cc', 'src/core/ext/filters/client_channel/retry_filter.cc',
'src/core/ext/filters/client_channel/retry_service_config.cc', 'src/core/ext/filters/client_channel/retry_service_config.cc',
'src/core/ext/filters/client_channel/retry_throttle.cc', 'src/core/ext/filters/client_channel/retry_throttle.cc',
@ -76,7 +76,7 @@ CORE_SOURCE_FILES = [
'src/core/ext/filters/client_channel/subchannel_stream_client.cc', 'src/core/ext/filters/client_channel/subchannel_stream_client.cc',
'src/core/ext/filters/deadline/deadline_filter.cc', 'src/core/ext/filters/deadline/deadline_filter.cc',
'src/core/ext/filters/fault_injection/fault_injection_filter.cc', 'src/core/ext/filters/fault_injection/fault_injection_filter.cc',
'src/core/ext/filters/fault_injection/service_config_parser.cc', 'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
'src/core/ext/filters/http/client/http_client_filter.cc', 'src/core/ext/filters/http/client/http_client_filter.cc',
'src/core/ext/filters/http/client_authority_filter.cc', 'src/core/ext/filters/http/client_authority_filter.cc',
'src/core/ext/filters/http/http_filters_plugin.cc', 'src/core/ext/filters/http/http_filters_plugin.cc',

@ -60,8 +60,22 @@ grpc_cc_test(
) )
grpc_cc_test( grpc_cc_test(
name = "service_config_test", name = "client_channel_service_config_test",
srcs = ["service_config_test.cc"], srcs = ["client_channel_service_config_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)
grpc_cc_test(
name = "retry_service_config_test",
srcs = ["retry_service_config_test.cc"],
external_deps = [ external_deps = [
"gtest", "gtest",
], ],

@ -0,0 +1,315 @@
//
// 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/ext/filters/client_channel/client_channel_service_config.h"
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "gtest/gtest.h"
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/service_config/service_config.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/test_config.h"
namespace grpc_core {
namespace testing {
// A regular expression to enter referenced or child errors.
#define CHILD_ERROR_TAG ".*children.*"
class ClientChannelParserTest : public ::testing::Test {
protected:
void SetUp() override {
parser_index_ =
CoreConfiguration::Get().service_config_parser().GetParserIndex(
"client_channel");
}
size_t parser_index_;
};
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
auto lb_config = parsed_config->parsed_lb_config();
EXPECT_EQ(lb_config->name(), "pick_first");
}
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
const char* test_json =
"{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
auto parsed_config = static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
auto lb_config = parsed_config->parsed_lb_config();
EXPECT_EQ(lb_config->name(), "round_robin");
}
TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
const char* test_json =
"{\"loadBalancingConfig\": "
"[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
auto lb_config = parsed_config->parsed_lb_config();
EXPECT_EQ(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"
" \"xdsLbPolicy\": [{\"round_robin\":{}}]\n"
" } }\n"
" ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
auto lb_config = parsed_config->parsed_lb_config();
EXPECT_EQ(lb_config->name(), "xds_cluster_resolver_experimental");
}
TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingConfig error:"
"No known policies in list: unknown]")
<< service_config.status();
}
TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
const char* test_json =
"{\"loadBalancingConfig\": ["
" {\"grpclb\":{\"childPolicy\":1}},"
" {\"round_robin\":{}}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingConfig error:"
"errors validating grpclb LB policy config: ["
"field:childPolicy error:type should be array]]")
<< service_config.status();
}
TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
}
TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
}
TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingPolicy error:unknown LB policy \"unknown\"]")
<< service_config.status();
}
TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) {
const char* test_json =
"{\"loadBalancingPolicy\":\"xds_cluster_resolver_experimental\"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingPolicy error:LB policy "
"\"xds_cluster_resolver_experimental\" requires a config. Please "
"use loadBalancingConfig instead.]")
<< service_config.status();
}
TEST_F(ClientChannelParserTest, ValidTimeout) {
const char* test_json =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
" ],\n"
" \"timeout\": \"5s\"\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = ((*vector_ptr)[parser_index_]).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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].timeout "
"error:Not a duration (no s suffix)]")
<< service_config.status();
}
TEST_F(ClientChannelParserTest, ValidWaitForReady) {
const char* test_json =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
" ],\n"
" \"waitForReady\": true\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = ((*vector_ptr)[parser_index_]).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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].waitForReady error:is not a boolean]")
<< service_config.status();
}
TEST_F(ClientChannelParserTest, ValidHealthCheck) {
const char* test_json =
"{\n"
" \"healthCheckConfig\": {\n"
" \"serviceName\": \"health_check_service_name\"\n"
" }\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config =
static_cast<internal::ClientChannelGlobalParsedConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"JSON parsing failed: ["
"duplicate key \"healthCheckConfig\" at index 104]")
<< service_config.status();
}
} // 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;
}

@ -0,0 +1,712 @@
//
// 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/ext/filters/client_channel/retry_service_config.h"
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "gtest/gtest.h"
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include <grpc/status.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/time.h"
#include "src/core/lib/service_config/service_config.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/test_config.h"
namespace grpc_core {
namespace testing {
class RetryParserTest : public ::testing::Test {
protected:
void SetUp() override {
parser_index_ =
CoreConfiguration::Get().service_config_parser().GetParserIndex(
"retry");
}
size_t parser_index_;
};
TEST_F(RetryParserTest, ValidRetryThrottling) {
const char* test_json =
"{\n"
" \"retryThrottling\": {\n"
" \"maxTokens\": 2,\n"
" \"tokenRatio\": 1.0\n"
" }\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* parsed_config = static_cast<internal::RetryGlobalConfig*>(
(*service_config)->GetGlobalParsedConfig(parser_index_));
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:retryThrottling.maxTokens error:field not present; "
"field:retryThrottling.tokenRatio error:field not present]")
<< service_config.status();
}
TEST_F(RetryParserTest, InvalidRetryThrottlingNegativeMaxTokens) {
const char* test_json =
"{\n"
" \"retryThrottling\": {\n"
" \"maxTokens\": -2,\n"
" \"tokenRatio\": 1.0\n"
" }\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:retryThrottling.maxTokens error:"
"failed to parse non-negative number]")
<< service_config.status();
}
TEST_F(RetryParserTest, InvalidRetryThrottlingInvalidTokenRatio) {
const char* test_json =
"{\n"
" \"retryThrottling\": {\n"
" \"maxTokens\": 2,\n"
" \"tokenRatio\": -1\n"
" }\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:retryThrottling.tokenRatio error:"
"could not parse as a number]");
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
const auto* parsed_config = static_cast<internal::RetryMethodConfig*>(
((*vector_ptr)[parser_index_]).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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy error:is not an object]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.backoffMultiplier "
"error:field not present; "
"field:methodConfig[0].retryPolicy.initialBackoff "
"error:field not present; "
"field:methodConfig[0].retryPolicy.maxAttempts "
"error:field not present; "
"field:methodConfig[0].retryPolicy.maxBackoff "
"error:field not present]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.maxAttempts "
"error:failed to parse number]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.maxAttempts "
"error:must be at least 2]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.initialBackoff "
"error:Not a duration (no s suffix)]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.initialBackoff "
"error:must be greater than 0]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.maxBackoff "
"error:Not a duration (no s suffix)]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.maxBackoff "
"error:must be greater than 0]")
<< service_config.status();
}
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\": [],\n"
" \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
" }\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.backoffMultiplier "
"error:is not a number]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.backoffMultiplier "
"error:must be greater than 0]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.retryableStatusCodes "
"error:must be non-empty]")
<< service_config.status();
}
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.retryableStatusCodes "
"error:is not an array]")
<< service_config.status();
}
TEST_F(RetryParserTest,
InvalidRetryPolicyRetryableStatusCodesElementsWrongType) {
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\": [true, 2]\n"
" }\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.retryableStatusCodes "
"error:must be non-empty; "
"field:methodConfig[0].retryPolicy.retryableStatusCodes[0] "
"error:is not a string; "
"field:methodConfig[0].retryPolicy.retryableStatusCodes[1] "
"error:is not a string]")
<< service_config.status();
}
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\", \"BAR\"]\n"
" }\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.retryableStatusCodes "
"error:must be non-empty; "
"field:methodConfig[0].retryPolicy.retryableStatusCodes[0] "
"error:failed to parse status code; "
"field:methodConfig[0].retryPolicy.retryableStatusCodes[1] "
"error:failed to parse status code]")
<< service_config.status();
}
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"
"}";
const ChannelArgs args =
ChannelArgs().Set(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
const auto* parsed_config = static_cast<internal::RetryMethodConfig*>(
((*vector_ptr)[parser_index_]).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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
const auto* parsed_config = static_cast<internal::RetryMethodConfig*>(
((*vector_ptr)[parser_index_]).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"
"}";
const ChannelArgs args =
ChannelArgs().Set(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
const auto* parsed_config = static_cast<internal::RetryMethodConfig*>(
((*vector_ptr)[parser_index_]).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"
"}";
const ChannelArgs args =
ChannelArgs().Set(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.perAttemptRecvTimeout "
"error:Not a duration (no s suffix)]")
<< service_config.status();
}
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"
"}";
const ChannelArgs args =
ChannelArgs().Set(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.perAttemptRecvTimeout "
"error:is not a string]")
<< service_config.status();
}
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"
"}";
const ChannelArgs args =
ChannelArgs().Set(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].retryPolicy.perAttemptRecvTimeout "
"error:must be greater than 0]")
<< service_config.status();
}
} // 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;
}

@ -14,11 +14,8 @@
// limitations under the License. // limitations under the License.
// //
#include <string>
#include "absl/status/status.h" #include "absl/status/status.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -111,15 +108,14 @@ TEST_F(RlsConfigParsingTest, TopLevelFieldsWrongTypes) {
auto service_config = auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
service_config.status().message(), "errors validating service config: ["
::testing::HasSubstr( "field:loadBalancingConfig "
"errors validing RLS LB policy config: [" "error:errors validing RLS LB policy config: ["
"field:childPolicy error:is not an array; " "field:childPolicy error:is not an array; "
"field:childPolicyConfigTargetFieldName error:is not a string; " "field:childPolicyConfigTargetFieldName error:is not a string; "
"field:routeLookupChannelServiceConfig error:" "field:routeLookupChannelServiceConfig error:is not an object; "
"INVALID_ARGUMENT:JSON value is not an object; " "field:routeLookupConfig error:is not an object]]")
"field:routeLookupConfig error:is not an object]"))
<< service_config.status(); << service_config.status();
} }
@ -191,17 +187,13 @@ TEST_F(RlsConfigParsingTest, InvalidRlsChannelServiceConfig) {
auto service_config = auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex( "field:loadBalancingConfig "
"errors validing RLS LB policy config: \\[" "error:errors validing RLS LB policy config: ["
"field:routeLookupChannelServiceConfig error:" "field:routeLookupChannelServiceConfig.loadBalancingPolicy "
"INVALID_ARGUMENT:Service config parsing errors: \\[" "error:unknown LB policy \"unknown\"; "
"error parsing client channel global parameters: " "field:routeLookupConfig error:field not present]]")
"UNKNOWN:Client channel global parser"
".*children:.*"
"\\[UNKNOWN:field:loadBalancingPolicy error:Unknown lb policy.*"
"field:routeLookupConfig error:field not present\\]"))
<< service_config.status(); << service_config.status();
} }

File diff suppressed because it is too large Load Diff

@ -14,10 +14,8 @@
#include "src/core/ext/filters/rbac/rbac_service_config_parser.h" #include "src/core/ext/filters/rbac/rbac_service_config_parser.h"
#include <string>
#include "absl/status/status.h" #include "absl/status/status.h"
#include "gmock/gmock.h" #include "absl/status/statusor.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <grpc/grpc.h> #include <grpc/grpc.h>
@ -28,9 +26,6 @@
#include "src/core/lib/service_config/service_config_impl.h" #include "src/core/lib/service_config/service_config_impl.h"
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
// A regular expression to enter referenced or child errors.
#define CHILD_ERROR_TAG ".*children.*"
namespace grpc_core { namespace grpc_core {
namespace testing { namespace testing {
namespace { namespace {
@ -148,10 +143,9 @@ TEST(RbacServiceConfigParsingTest, BadRbacPolicyType) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy error:is not an array]")
"field:rbacPolicy error:type should be ARRAY"))
<< service_config.status(); << service_config.status();
} }
@ -168,11 +162,9 @@ TEST(RbacServiceConfigParsingTest, BadRulesType) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules error:is not an object]")
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"field:rules error:type should be OBJECT"))
<< service_config.status(); << service_config.status();
} }
@ -194,12 +186,12 @@ TEST(RbacServiceConfigParsingTest, BadActionAndPolicyType) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.action "
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG "error:is not a number; "
"field:action error:type should be NUMBER.*" "field:methodConfig[0].rbacPolicy[0].rules.policies "
"field:policies error:type should be OBJECT")) "error:is not an object]")
<< service_config.status(); << service_config.status();
} }
@ -224,13 +216,12 @@ TEST(RbacServiceConfigParsingTest, MissingPermissionAndPrincipals) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG ".permissions error:field not present; "
"policies key:'policy'" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:permissions error:does not exist.*" ".principals error:field not present]")
"field:principals error:does not exist"))
<< service_config.status(); << service_config.status();
} }
@ -257,13 +248,12 @@ TEST(RbacServiceConfigParsingTest, EmptyPrincipalAndPermission) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex( "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"Rbac parser" CHILD_ERROR_TAG "rbacPolicy\\[0\\]" CHILD_ERROR_TAG ".permissions[0] error:no valid rule found; "
"policies key:'policy'" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[0\\]" CHILD_ERROR_TAG "No valid rule found.*" ".principals[0] error:no valid id found]")
"principals\\[0\\]" CHILD_ERROR_TAG "No valid id found"))
<< service_config.status(); << service_config.status();
} }
@ -370,53 +360,51 @@ TEST(RbacServiceConfigParsingTest, VariousPermissionsAndPrincipalsBadTypes) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex( "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"Rbac parser" CHILD_ERROR_TAG "rbacPolicy\\[0\\]" CHILD_ERROR_TAG ".permissions[0].andRules error:is not an object; "
"policies key:'policy'" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[0\\]" CHILD_ERROR_TAG ".permissions[1].orRules error:is not an object; "
"field:andRules error:type should be OBJECT.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[1\\]" CHILD_ERROR_TAG ".permissions[2].any error:is not a boolean; "
"field:orRules error:type should be OBJECT.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[2\\]" CHILD_ERROR_TAG ".permissions[3].header error:is not an object; "
"field:any error:type should be BOOLEAN.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[3\\]" CHILD_ERROR_TAG ".permissions[4].urlPath error:is not an object; "
"field:header error:type should be OBJECT.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[4\\]" CHILD_ERROR_TAG ".permissions[5].destinationIp error:is not an object; "
"field:urlPath error:type should be OBJECT.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[5\\]" CHILD_ERROR_TAG ".permissions[6].destinationPort "
"field:destinationIp error:type should be OBJECT.*" "error:failed to parse non-negative number; "
"permissions\\[6\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:destinationPort error:failed to parse.*" ".permissions[7].metadata error:is not an object; "
"permissions\\[7\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:metadata error:type should be OBJECT.*" ".permissions[8].notRule error:is not an object; "
"permissions\\[8\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:notRule error:type should be OBJECT.*" ".permissions[9].requestedServerName error:is not an object; "
"permissions\\[9\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:requestedServerName error:type should be OBJECT.*" ".principals[0].andIds error:is not an object; "
"principals\\[0\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:andIds error:type should be OBJECT.*" ".principals[10].notId error:is not an object; "
"principals\\[1\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:orIds error:type should be OBJECT.*" ".principals[1].orIds error:is not an object; "
"principals\\[2\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:any error:type should be BOOLEAN.*" ".principals[2].any error:is not a boolean; "
"principals\\[3\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:authenticated error:type should be OBJECT.*" ".principals[3].authenticated error:is not an object; "
"principals\\[4\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:sourceIp error:type should be OBJECT.*" ".principals[4].sourceIp error:is not an object; "
"principals\\[5\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:directRemoteIp error:type should be OBJECT.*" ".principals[5].directRemoteIp error:is not an object; "
"principals\\[6\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:remoteIp error:type should be OBJECT.*" ".principals[6].remoteIp error:is not an object; "
"principals\\[7\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:header error:type should be OBJECT.*" ".principals[7].header error:is not an object; "
"principals\\[8\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:urlPath error:type should be OBJECT.*" ".principals[8].urlPath error:is not an object; "
"principals\\[9\\]" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:metadata error:type should be OBJECT.*" ".principals[9].metadata error:is not an object]")
"principals\\[10\\]" CHILD_ERROR_TAG
"field:notId error:type should be OBJECT.*"))
<< service_config.status(); << service_config.status();
} }
@ -484,7 +472,8 @@ TEST(RbacServiceConfigParsingTest, HeaderMatcherBadTypes) {
" {\"header\":{\"name\":\"name\", \"presentMatch\":1}},\n" " {\"header\":{\"name\":\"name\", \"presentMatch\":1}},\n"
" {\"header\":{\"name\":\"name\", \"prefixMatch\":1}},\n" " {\"header\":{\"name\":\"name\", \"prefixMatch\":1}},\n"
" {\"header\":{\"name\":\"name\", \"suffixMatch\":1}},\n" " {\"header\":{\"name\":\"name\", \"suffixMatch\":1}},\n"
" {\"header\":{\"name\":\"name\", \"containsMatch\":1}}\n" " {\"header\":{\"name\":\"name\", \"containsMatch\":1}},\n"
" {\"header\":{\"name\":\"name\"}}\n"
" ],\n" " ],\n"
" \"principals\":[]\n" " \"principals\":[]\n"
" }\n" " }\n"
@ -496,26 +485,26 @@ TEST(RbacServiceConfigParsingTest, HeaderMatcherBadTypes) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex( "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"Rbac parser" CHILD_ERROR_TAG "rbacPolicy\\[0\\]" CHILD_ERROR_TAG ".permissions[0].header.exactMatch error:is not a string; "
"policies key:'policy'" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[0\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG ".permissions[0].header.invertMatch error:is not a boolean; "
"field:invertMatch error:type should be BOOLEAN.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:exactMatch error:type should be STRING.*" ".permissions[1].header.safeRegexMatch error:is not an object; "
"permissions\\[1\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:safeRegexMatch error:type should be OBJECT.*" ".permissions[2].header.rangeMatch error:is not an object; "
"permissions\\[2\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:rangeMatch error:type should be OBJECT.*" ".permissions[3].header.presentMatch error:is not a boolean; "
"permissions\\[3\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:presentMatch error:type should be BOOLEAN.*" ".permissions[4].header.prefixMatch error:is not a string; "
"permissions\\[4\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:prefixMatch error:type should be STRING.*" ".permissions[5].header.suffixMatch error:is not a string; "
"permissions\\[5\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:suffixMatch error:type should be STRING.*" ".permissions[6].header.containsMatch error:is not a string; "
"permissions\\[6\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:containsMatch error:type should be STRING.*")) ".permissions[7].header error:no valid matcher found]")
<< service_config.status(); << service_config.status();
} }
@ -578,7 +567,8 @@ TEST(RbacServiceConfigParsingTest, StringMatcherBadTypes) {
" {\"requestedServerName\":{\"prefix\":1}},\n" " {\"requestedServerName\":{\"prefix\":1}},\n"
" {\"requestedServerName\":{\"suffix\":1}},\n" " {\"requestedServerName\":{\"suffix\":1}},\n"
" {\"requestedServerName\":{\"safeRegex\":1}},\n" " {\"requestedServerName\":{\"safeRegex\":1}},\n"
" {\"requestedServerName\":{\"contains\":1}}\n" " {\"requestedServerName\":{\"contains\":1}},\n"
" {\"requestedServerName\":{}}\n"
" ],\n" " ],\n"
" \"principals\":[]\n" " \"principals\":[]\n"
" }\n" " }\n"
@ -590,27 +580,27 @@ TEST(RbacServiceConfigParsingTest, StringMatcherBadTypes) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1); ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json); auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT( EXPECT_EQ(service_config.status().message(),
std::string(service_config.status().message()), "errors validating service config: ["
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG ".permissions[0].requestedServerName.exact error:is not a string; "
"policies key:'policy'" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"permissions\\[0\\]" CHILD_ERROR_TAG ".permissions[0].requestedServerName.ignoreCase "
"requestedServerName" CHILD_ERROR_TAG "error:is not a boolean; "
"field:ignoreCase error:type should be BOOLEAN.*" "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:exact error:type should be STRING.*" ".permissions[1].requestedServerName.prefix "
"permissions\\[1\\]" CHILD_ERROR_TAG "error:is not a string; "
"requestedServerName" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:prefix error:type should be STRING.*" ".permissions[2].requestedServerName.suffix "
"permissions\\[2\\]" CHILD_ERROR_TAG "error:is not a string; "
"requestedServerName" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:suffix error:type should be STRING.*" ".permissions[3].requestedServerName.safeRegex "
"permissions\\[3\\]" CHILD_ERROR_TAG "error:is not an object; "
"requestedServerName" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:safeRegex error:type should be OBJECT.*" ".permissions[4].requestedServerName.contains "
"permissions\\[4\\]" CHILD_ERROR_TAG "error:is not a string; "
"requestedServerName" CHILD_ERROR_TAG "field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
"field:contains error:type should be STRING.*")) ".permissions[5].requestedServerName error:no valid matcher found]")
<< service_config.status(); << service_config.status();
} }

@ -49,6 +49,7 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
TypeParam value = 0; TypeParam value = 0;
TypeParam optional_value = 0; TypeParam optional_value = 0;
absl::optional<TypeParam> absl_optional_value; absl::optional<TypeParam> absl_optional_value;
std::unique_ptr<TypeParam> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -57,6 +58,7 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -79,6 +81,13 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
EXPECT_EQ(test_struct->value, 5); EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 0); EXPECT_EQ(test_struct->optional_value, 0);
EXPECT_FALSE(test_struct->absl_optional_value.has_value()); EXPECT_FALSE(test_struct->absl_optional_value.has_value());
// Fails to parse number from JSON string.
test_struct = Parse<TestStruct>("{\"value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(
test_struct.status().message(),
"errors validating JSON: [field:value error:failed to parse number]")
<< test_struct.status();
// Fails if required field is not present. // Fails if required field is not present.
test_struct = Parse<TestStruct>("{}"); test_struct = Parse<TestStruct>("{}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
@ -88,20 +97,23 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": 5, \"optional_value\": 7, " "{\"value\": 5, \"optional_value\": 7, "
"\"absl_optional_value\": 9}"); "\"absl_optional_value\": 9, \"unique_ptr_value\": 11}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(test_struct->value, 5); EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 7); EXPECT_EQ(test_struct->optional_value, 7);
EXPECT_EQ(test_struct->absl_optional_value, 9); EXPECT_EQ(test_struct->absl_optional_value, 9);
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_EQ(*test_struct->unique_ptr_value, 11);
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": {}, " "{\"value\": [], \"optional_value\": {}, "
"\"absl_optional_value\": true}"); "\"absl_optional_value\": true, \"unique_ptr_value\": false}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not a number; " "field:absl_optional_value error:is not a number; "
"field:optional_value error:is not a number; " "field:optional_value error:is not a number; "
"field:unique_ptr_value error:is not a number; "
"field:value error:is not a number]") "field:value error:is not a number]")
<< test_struct.status(); << test_struct.status();
} }
@ -125,6 +137,7 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
TypeParam value = 0; TypeParam value = 0;
TypeParam optional_value = 0; TypeParam optional_value = 0;
absl::optional<TypeParam> absl_optional_value; absl::optional<TypeParam> absl_optional_value;
std::unique_ptr<TypeParam> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -133,6 +146,7 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -156,6 +170,13 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
EXPECT_EQ(test_struct->value, 5); EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 0); EXPECT_EQ(test_struct->optional_value, 0);
EXPECT_FALSE(test_struct->absl_optional_value.has_value()); EXPECT_FALSE(test_struct->absl_optional_value.has_value());
// Fails to parse number from JSON string.
test_struct = Parse<TestStruct>("{\"value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: ["
"field:value error:failed to parse non-negative number]")
<< test_struct.status();
// Fails if required field is not present. // Fails if required field is not present.
test_struct = Parse<TestStruct>("{}"); test_struct = Parse<TestStruct>("{}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
@ -165,21 +186,24 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": 5, \"optional_value\": 7, " "{\"value\": 5, \"optional_value\": 7, "
"\"absl_optional_value\": 9}"); "\"absl_optional_value\": 9, \"unique_ptr_value\": 11}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(test_struct->value, 5); EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 7); EXPECT_EQ(test_struct->optional_value, 7);
ASSERT_TRUE(test_struct->absl_optional_value.has_value()); ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_EQ(*test_struct->absl_optional_value, 9); EXPECT_EQ(*test_struct->absl_optional_value, 9);
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_EQ(*test_struct->unique_ptr_value, 11);
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": {}, " "{\"value\": [], \"optional_value\": {}, "
"\"absl_optional_value\": true}"); "\"absl_optional_value\": true, \"unique_ptr_value\": false}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not a number; " "field:absl_optional_value error:is not a number; "
"field:optional_value error:is not a number; " "field:optional_value error:is not a number; "
"field:unique_ptr_value error:is not a number; "
"field:value error:is not a number]") "field:value error:is not a number]")
<< test_struct.status(); << test_struct.status();
} }
@ -203,6 +227,7 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
TypeParam value = 0; TypeParam value = 0;
TypeParam optional_value = 0; TypeParam optional_value = 0;
absl::optional<TypeParam> absl_optional_value; absl::optional<TypeParam> absl_optional_value;
std::unique_ptr<TypeParam> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -211,6 +236,7 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -233,6 +259,13 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
EXPECT_NEAR(test_struct->value, 5.2, 0.0001); EXPECT_NEAR(test_struct->value, 5.2, 0.0001);
EXPECT_EQ(test_struct->optional_value, 0); EXPECT_EQ(test_struct->optional_value, 0);
EXPECT_FALSE(test_struct->absl_optional_value.has_value()); EXPECT_FALSE(test_struct->absl_optional_value.has_value());
// Fails to parse number from JSON string.
test_struct = Parse<TestStruct>("{\"value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: ["
"field:value error:failed to parse floating-point number]")
<< test_struct.status();
// Fails if required field is not present. // Fails if required field is not present.
test_struct = Parse<TestStruct>("{}"); test_struct = Parse<TestStruct>("{}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
@ -242,21 +275,24 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": 5.2, \"optional_value\": 7.5, " "{\"value\": 5.2, \"optional_value\": 7.5, "
"\"absl_optional_value\": 9.8}"); "\"absl_optional_value\": 9.8, \"unique_ptr_value\": 11.5}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_NEAR(test_struct->value, 5.2, 0.0001); EXPECT_NEAR(test_struct->value, 5.2, 0.0001);
EXPECT_NEAR(test_struct->optional_value, 7.5, 0.0001); EXPECT_NEAR(test_struct->optional_value, 7.5, 0.0001);
ASSERT_TRUE(test_struct->absl_optional_value.has_value()); ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_NEAR(*test_struct->absl_optional_value, 9.8, 0.0001); EXPECT_NEAR(*test_struct->absl_optional_value, 9.8, 0.0001);
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_NEAR(*test_struct->unique_ptr_value, 11.5, 0.0001);
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": {}, " "{\"value\": [], \"optional_value\": {}, "
"\"absl_optional_value\": true}"); "\"absl_optional_value\": true, \"unique_ptr_value\": false}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not a number; " "field:absl_optional_value error:is not a number; "
"field:optional_value error:is not a number; " "field:optional_value error:is not a number; "
"field:unique_ptr_value error:is not a number; "
"field:value error:is not a number]") "field:value error:is not a number]")
<< test_struct.status(); << test_struct.status();
} }
@ -275,6 +311,7 @@ TEST(JsonObjectLoader, BooleanFields) {
bool value = false; bool value = false;
bool optional_value = true; bool optional_value = true;
absl::optional<bool> absl_optional_value; absl::optional<bool> absl_optional_value;
std::unique_ptr<bool> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -283,6 +320,7 @@ TEST(JsonObjectLoader, BooleanFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -308,20 +346,23 @@ TEST(JsonObjectLoader, BooleanFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": true, \"optional_value\": false," "{\"value\": true, \"optional_value\": false,"
"\"absl_optional_value\": true}"); "\"absl_optional_value\": true, \"unique_ptr_value\": false}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(test_struct->value, true); EXPECT_EQ(test_struct->value, true);
EXPECT_EQ(test_struct->optional_value, false); EXPECT_EQ(test_struct->optional_value, false);
EXPECT_EQ(test_struct->absl_optional_value, true); EXPECT_EQ(test_struct->absl_optional_value, true);
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_EQ(*test_struct->unique_ptr_value, false);
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": {}, " "{\"value\": [], \"optional_value\": {}, "
"\"absl_optional_value\": 1}"); "\"absl_optional_value\": 1, \"unique_ptr_value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not a boolean; " "field:absl_optional_value error:is not a boolean; "
"field:optional_value error:is not a boolean; " "field:optional_value error:is not a boolean; "
"field:unique_ptr_value error:is not a boolean; "
"field:value error:is not a boolean]") "field:value error:is not a boolean]")
<< test_struct.status(); << test_struct.status();
} }
@ -335,6 +376,7 @@ TEST(JsonObjectLoader, StringFields) {
std::string value; std::string value;
std::string optional_value; std::string optional_value;
absl::optional<std::string> absl_optional_value; absl::optional<std::string> absl_optional_value;
std::unique_ptr<std::string> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -343,6 +385,7 @@ TEST(JsonObjectLoader, StringFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -362,20 +405,23 @@ TEST(JsonObjectLoader, StringFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": \"foo\", \"optional_value\": \"bar\"," "{\"value\": \"foo\", \"optional_value\": \"bar\","
"\"absl_optional_value\": \"baz\"}"); "\"absl_optional_value\": \"baz\", \"unique_ptr_value\": \"quux\"}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(test_struct->value, "foo"); EXPECT_EQ(test_struct->value, "foo");
EXPECT_EQ(test_struct->optional_value, "bar"); EXPECT_EQ(test_struct->optional_value, "bar");
EXPECT_EQ(test_struct->absl_optional_value, "baz"); EXPECT_EQ(test_struct->absl_optional_value, "baz");
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_EQ(*test_struct->unique_ptr_value, "quux");
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": {}, " "{\"value\": [], \"optional_value\": {}, "
"\"absl_optional_value\": 1}"); "\"absl_optional_value\": 1, \"unique_ptr_value\": true}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not a string; " "field:absl_optional_value error:is not a string; "
"field:optional_value error:is not a string; " "field:optional_value error:is not a string; "
"field:unique_ptr_value error:is not a string; "
"field:value error:is not a string]") "field:value error:is not a string]")
<< test_struct.status(); << test_struct.status();
} }
@ -389,6 +435,7 @@ TEST(JsonObjectLoader, DurationFields) {
Duration value = Duration::Zero(); Duration value = Duration::Zero();
Duration optional_value = Duration::Zero(); Duration optional_value = Duration::Zero();
absl::optional<Duration> absl_optional_value; absl::optional<Duration> absl_optional_value;
std::unique_ptr<Duration> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -397,6 +444,7 @@ TEST(JsonObjectLoader, DurationFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -441,20 +489,23 @@ TEST(JsonObjectLoader, DurationFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": \"3s\", \"optional_value\": \"3.2s\", " "{\"value\": \"3s\", \"optional_value\": \"3.2s\", "
"\"absl_optional_value\": \"10s\"}"); "\"absl_optional_value\": \"10s\", \"unique_ptr_value\": \"11s\"}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(test_struct->value, Duration::Seconds(3)); EXPECT_EQ(test_struct->value, Duration::Seconds(3));
EXPECT_EQ(test_struct->optional_value, Duration::Milliseconds(3200)); EXPECT_EQ(test_struct->optional_value, Duration::Milliseconds(3200));
EXPECT_EQ(test_struct->absl_optional_value, Duration::Seconds(10)); EXPECT_EQ(test_struct->absl_optional_value, Duration::Seconds(10));
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_EQ(*test_struct->unique_ptr_value, Duration::Seconds(11));
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": {}, " "{\"value\": [], \"optional_value\": {}, "
"\"absl_optional_value\": 1}"); "\"absl_optional_value\": 1, \"unique_ptr_value\": true}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not a string; " "field:absl_optional_value error:is not a string; "
"field:optional_value error:is not a string; " "field:optional_value error:is not a string; "
"field:unique_ptr_value error:is not a string; "
"field:value error:is not a string]") "field:value error:is not a string]")
<< test_struct.status(); << test_struct.status();
} }
@ -468,6 +519,7 @@ TEST(JsonObjectLoader, JsonObjectFields) {
Json::Object value; Json::Object value;
Json::Object optional_value; Json::Object optional_value;
absl::optional<Json::Object> absl_optional_value; absl::optional<Json::Object> absl_optional_value;
std::unique_ptr<Json::Object> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -476,6 +528,7 @@ TEST(JsonObjectLoader, JsonObjectFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -495,21 +548,24 @@ TEST(JsonObjectLoader, JsonObjectFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": {\"a\":1}, \"optional_value\": {\"b\":2}, " "{\"value\": {\"a\":1}, \"optional_value\": {\"b\":2}, "
"\"absl_optional_value\": {\"c\":3}}"); "\"absl_optional_value\": {\"c\":3}, \"unique_ptr_value\": {\"d\":4}}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(Json{test_struct->value}.Dump(), "{\"a\":1}"); EXPECT_EQ(Json{test_struct->value}.Dump(), "{\"a\":1}");
EXPECT_EQ(Json{test_struct->optional_value}.Dump(), "{\"b\":2}"); EXPECT_EQ(Json{test_struct->optional_value}.Dump(), "{\"b\":2}");
ASSERT_TRUE(test_struct->absl_optional_value.has_value()); ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_EQ(Json{*test_struct->absl_optional_value}.Dump(), "{\"c\":3}"); EXPECT_EQ(Json{*test_struct->absl_optional_value}.Dump(), "{\"c\":3}");
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_EQ(Json{*test_struct->unique_ptr_value}.Dump(), "{\"d\":4}");
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": true, " "{\"value\": [], \"optional_value\": true, "
"\"absl_optional_value\": 1}"); "\"absl_optional_value\": 1, \"unique_ptr_value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not an object; " "field:absl_optional_value error:is not an object; "
"field:optional_value error:is not an object; " "field:optional_value error:is not an object; "
"field:unique_ptr_value error:is not an object; "
"field:value error:is not an object]") "field:value error:is not an object]")
<< test_struct.status(); << test_struct.status();
} }
@ -523,6 +579,7 @@ TEST(JsonObjectLoader, MapFields) {
std::map<std::string, int32_t> value; std::map<std::string, int32_t> value;
std::map<std::string, std::string> optional_value; std::map<std::string, std::string> optional_value;
absl::optional<std::map<std::string, bool>> absl_optional_value; absl::optional<std::map<std::string, bool>> absl_optional_value;
std::unique_ptr<std::map<std::string, int32_t>> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -531,6 +588,7 @@ TEST(JsonObjectLoader, MapFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -551,7 +609,8 @@ TEST(JsonObjectLoader, MapFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": {\"a\":1}, \"optional_value\": {\"b\":\"foo\"}, " "{\"value\": {\"a\":1}, \"optional_value\": {\"b\":\"foo\"}, "
"\"absl_optional_value\": {\"c\":true}}"); "\"absl_optional_value\": {\"c\":true}, "
"\"unique_ptr_value\": {\"d\":4}}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_THAT(test_struct->value, EXPECT_THAT(test_struct->value,
::testing::ElementsAre(::testing::Pair("a", 1))); ::testing::ElementsAre(::testing::Pair("a", 1)));
@ -560,15 +619,19 @@ TEST(JsonObjectLoader, MapFields) {
ASSERT_TRUE(test_struct->absl_optional_value.has_value()); ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_THAT(*test_struct->absl_optional_value, EXPECT_THAT(*test_struct->absl_optional_value,
::testing::ElementsAre(::testing::Pair("c", true))); ::testing::ElementsAre(::testing::Pair("c", true)));
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_THAT(*test_struct->unique_ptr_value,
::testing::ElementsAre(::testing::Pair("d", 4)));
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [], \"optional_value\": true, " "{\"value\": [], \"optional_value\": true, "
"\"absl_optional_value\": 1}"); "\"absl_optional_value\": 1, \"unique_ptr_value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not an object; " "field:absl_optional_value error:is not an object; "
"field:optional_value error:is not an object; " "field:optional_value error:is not an object; "
"field:unique_ptr_value error:is not an object; "
"field:value error:is not an object]") "field:value error:is not an object]")
<< test_struct.status(); << test_struct.status();
// Wrong JSON type for map value. // Wrong JSON type for map value.
@ -593,6 +656,7 @@ TEST(JsonObjectLoader, VectorFields) {
std::vector<int32_t> value; std::vector<int32_t> value;
std::vector<std::string> optional_value; std::vector<std::string> optional_value;
absl::optional<std::vector<bool>> absl_optional_value; absl::optional<std::vector<bool>> absl_optional_value;
std::unique_ptr<std::vector<int32_t>> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -601,6 +665,7 @@ TEST(JsonObjectLoader, VectorFields) {
.OptionalField("optional_value", &TestStruct::optional_value) .OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value", .OptionalField("absl_optional_value",
&TestStruct::absl_optional_value) &TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish(); .Finish();
return loader; return loader;
} }
@ -620,7 +685,8 @@ TEST(JsonObjectLoader, VectorFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": [4, 5, 6], \"optional_value\": [\"foo\", \"bar\"], " "{\"value\": [4, 5, 6], \"optional_value\": [\"foo\", \"bar\"], "
"\"absl_optional_value\": [true, false, true]}"); "\"absl_optional_value\": [true, false, true], "
"\"unique_ptr_value\": [1, 2, 3]}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_THAT(test_struct->value, ::testing::ElementsAre(4, 5, 6)); EXPECT_THAT(test_struct->value, ::testing::ElementsAre(4, 5, 6));
EXPECT_THAT(test_struct->optional_value, EXPECT_THAT(test_struct->optional_value,
@ -628,15 +694,18 @@ TEST(JsonObjectLoader, VectorFields) {
ASSERT_TRUE(test_struct->absl_optional_value.has_value()); ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_THAT(*test_struct->absl_optional_value, EXPECT_THAT(*test_struct->absl_optional_value,
::testing::ElementsAre(true, false, true)); ::testing::ElementsAre(true, false, true));
ASSERT_NE(test_struct->unique_ptr_value, nullptr);
EXPECT_THAT(*test_struct->unique_ptr_value, ::testing::ElementsAre(1, 2, 3));
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"value\": {}, \"optional_value\": true, " "{\"value\": {}, \"optional_value\": true, "
"\"absl_optional_value\": 1}"); "\"absl_optional_value\": 1, \"unique_ptr_value\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_value error:is not an array; " "field:absl_optional_value error:is not an array; "
"field:optional_value error:is not an array; " "field:optional_value error:is not an array; "
"field:unique_ptr_value error:is not an array; "
"field:value error:is not an array]") "field:value error:is not an array]")
<< test_struct.status(); << test_struct.status();
// Wrong JSON type for map value. // Wrong JSON type for map value.
@ -674,6 +743,7 @@ TEST(JsonObjectLoader, NestedStructFields) {
NestedStruct outer; NestedStruct outer;
NestedStruct optional_outer; NestedStruct optional_outer;
absl::optional<NestedStruct> absl_optional_outer; absl::optional<NestedStruct> absl_optional_outer;
std::unique_ptr<NestedStruct> unique_ptr_outer;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) { static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = static const auto* loader =
@ -682,6 +752,7 @@ TEST(JsonObjectLoader, NestedStructFields) {
.OptionalField("optional_outer", &TestStruct::optional_outer) .OptionalField("optional_outer", &TestStruct::optional_outer)
.OptionalField("absl_optional_outer", .OptionalField("absl_optional_outer",
&TestStruct::absl_optional_outer) &TestStruct::absl_optional_outer)
.OptionalField("unique_ptr_outer", &TestStruct::unique_ptr_outer)
.Finish(); .Finish();
return loader; return loader;
} }
@ -708,22 +779,26 @@ TEST(JsonObjectLoader, NestedStructFields) {
// Optional fields present. // Optional fields present.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"outer\": {\"inner\":1}, \"optional_outer\": {\"inner\":2}, " "{\"outer\": {\"inner\":1}, \"optional_outer\": {\"inner\":2}, "
"\"absl_optional_outer\": {\"inner\":3}}"); "\"absl_optional_outer\": {\"inner\":3}, "
"\"unique_ptr_outer\": {\"inner\":4}}");
ASSERT_TRUE(test_struct.ok()) << test_struct.status(); ASSERT_TRUE(test_struct.ok()) << test_struct.status();
EXPECT_EQ(test_struct->outer.inner, 1); EXPECT_EQ(test_struct->outer.inner, 1);
EXPECT_EQ(test_struct->optional_outer.inner, 2); EXPECT_EQ(test_struct->optional_outer.inner, 2);
ASSERT_TRUE(test_struct->absl_optional_outer.has_value()); ASSERT_TRUE(test_struct->absl_optional_outer.has_value());
EXPECT_EQ(test_struct->absl_optional_outer->inner, 3); EXPECT_EQ(test_struct->absl_optional_outer->inner, 3);
ASSERT_NE(test_struct->unique_ptr_outer, nullptr);
EXPECT_EQ(test_struct->unique_ptr_outer->inner, 4);
// Wrong JSON type. // Wrong JSON type.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
"{\"outer\": \"foo\", \"optional_outer\": true, " "{\"outer\": \"foo\", \"optional_outer\": true, "
"\"absl_optional_outer\": 1}"); "\"absl_optional_outer\": 1, \"unique_ptr_outer\": \"foo\"}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument); EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(test_struct.status().message(), EXPECT_EQ(test_struct.status().message(),
"errors validating JSON: [" "errors validating JSON: ["
"field:absl_optional_outer error:is not an object; " "field:absl_optional_outer error:is not an object; "
"field:optional_outer error:is not an object; " "field:optional_outer error:is not an object; "
"field:outer error:is not an object]") "field:outer error:is not an object; "
"field:unique_ptr_outer error:is not an object]")
<< test_struct.status(); << test_struct.status();
// Wrong JSON type for inner value. // Wrong JSON type for inner value.
test_struct = Parse<TestStruct>( test_struct = Parse<TestStruct>(
@ -774,6 +849,13 @@ TEST(JsonObjectLoader, BareBool) {
EXPECT_TRUE(*parsed); EXPECT_TRUE(*parsed);
} }
TEST(JsonObjectLoader, BareUniquePtr) {
auto parsed = Parse<std::unique_ptr<uint32_t>>("3");
ASSERT_TRUE(parsed.ok()) << parsed.status();
ASSERT_NE(*parsed, nullptr);
EXPECT_EQ(**parsed, 3);
}
TEST(JsonObjectLoader, BareVector) { TEST(JsonObjectLoader, BareVector) {
auto parsed = Parse<std::vector<int32_t>>("[1, 2, 3]"); auto parsed = Parse<std::vector<int32_t>>("[1, 2, 3]");
ASSERT_TRUE(parsed.ok()) << parsed.status(); ASSERT_TRUE(parsed.ok()) << parsed.status();

@ -0,0 +1,33 @@
# Copyright 2017 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.
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package")
grpc_package(name = "test/core/message_size")
licenses(["notice"])
grpc_cc_test(
name = "message_size_service_config_test",
srcs = ["message_size_service_config_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,125 @@
//
// 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 <stddef.h>
#include <memory>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "gtest/gtest.h"
#include <grpc/grpc.h>
#include <grpc/slice.h>
#include "src/core/ext/filters/message_size/message_size_filter.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/service_config/service_config.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/test_config.h"
namespace grpc_core {
namespace testing {
class MessageSizeParserTest : public ::testing::Test {
protected:
void SetUp() override {
parser_index_ =
CoreConfiguration::Get().service_config_parser().GetParserIndex(
"message_size");
}
size_t parser_index_;
};
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"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_NE(vector_ptr, nullptr);
auto parsed_config = static_cast<MessageSizeParsedConfig*>(
((*vector_ptr)[parser_index_]).get());
ASSERT_NE(parsed_config, nullptr);
EXPECT_EQ(parsed_config->max_send_size(), 1024U);
EXPECT_EQ(parsed_config->max_recv_size(), 1024U);
}
TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) {
const char* test_json =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
" ],\n"
" \"maxRequestMessageBytes\": -1024\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].maxRequestMessageBytes "
"error:failed to parse non-negative number]")
<< service_config.status();
}
TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) {
const char* test_json =
"{\n"
" \"methodConfig\": [ {\n"
" \"name\": [\n"
" { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
" ],\n"
" \"maxResponseMessageBytes\": {}\n"
" } ]\n"
"}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].maxResponseMessageBytes "
"error:is not a number]")
<< service_config.status();
}
} // 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;
}

@ -0,0 +1,33 @@
# Copyright 2017 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.
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package")
grpc_package(name = "test/core/service_config")
licenses(["notice"])
grpc_cc_test(
name = "service_config_test",
srcs = ["service_config_test.cc"],
external_deps = [
"gtest",
],
language = "C++",
deps = [
"//:gpr",
"//:grpc",
"//test/core/util:grpc_test_util",
],
)

@ -0,0 +1,468 @@
//
// 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 <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <grpc/grpc.h>
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/json/json.h"
#include "src/core/lib/json/json_args.h"
#include "src/core/lib/json/json_object_loader.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/test_config.h"
namespace grpc_core {
namespace testing {
// Set this channel arg to true to disable parsing.
#define GRPC_ARG_DISABLE_PARSING "disable_parsing"
class TestParsedConfig1 : public ServiceConfigParser::ParsedConfig {
public:
uint32_t value() const { return value_; }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<TestParsedConfig1>()
.OptionalField("global_param", &TestParsedConfig1::value_)
.Finish();
return loader;
}
private:
uint32_t value_;
};
class TestParser1 : public ServiceConfigParser::Parser {
public:
absl::string_view name() const override { return "test_parser_1"; }
std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
const ChannelArgs& args, const Json& json,
ValidationErrors* errors) override {
if (args.GetBool(GRPC_ARG_DISABLE_PARSING).value_or(false)) {
return nullptr;
}
return LoadFromJson<std::unique_ptr<TestParsedConfig1>>(json, JsonArgs(),
errors);
}
};
class TestParsedConfig2 : public ServiceConfigParser::ParsedConfig {
public:
uint32_t value() const { return value_; }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<TestParsedConfig2>()
.OptionalField("method_param", &TestParsedConfig2::value_)
.Finish();
return loader;
}
private:
uint32_t value_;
};
class TestParser2 : public ServiceConfigParser::Parser {
public:
absl::string_view name() const override { return "test_parser_2"; }
std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
const ChannelArgs& args, const Json& json,
ValidationErrors* errors) override {
if (args.GetBool(GRPC_ARG_DISABLE_PARSING).value_or(false)) {
return nullptr;
}
return LoadFromJson<std::unique_ptr<TestParsedConfig2>>(json, JsonArgs(),
errors);
}
};
class ServiceConfigTest : public ::testing::Test {
protected:
void SetUp() override {
builder_ = std::make_unique<CoreConfiguration::WithSubstituteBuilder>(
[](CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<TestParser1>());
builder->service_config_parser()->RegisterParser(
std::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);
}
private:
std::unique_ptr<CoreConfiguration::WithSubstituteBuilder> builder_;
};
TEST_F(ServiceConfigTest, JsonParseError) {
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), "");
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(std::string(service_config.status().message()),
::testing::StartsWith("JSON parsing failed"))
<< service_config.status();
}
TEST_F(ServiceConfigTest, EmptyConfig) {
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), "{}");
ASSERT_TRUE(service_config.ok()) << service_config.status();
EXPECT_EQ((*service_config)->json_string(), "{}");
}
TEST_F(ServiceConfigTest, SkipMethodConfigWithNoNameOrEmptyName) {
const char* test_json =
"{\"methodConfig\": ["
" {\"method_param\":1},"
" {\"name\":[], \"method_param\":1},"
" {\"name\":[{\"service\":\"TestServ\"}], \"method_param\":2}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
auto vector_ptr =
(*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod"));
ASSERT_EQ(vector_ptr->size(), 2UL);
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\"}]}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[1].name[0] "
"error:multiple method configs for path /TestServ/]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithNullMethod) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":\"TestServ\",\"method\":null}]},"
" {\"name\":[{\"service\":\"TestServ\"}]}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[1].name[0] "
"error:multiple method configs for path /TestServ/]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithEmptyMethod) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":\"TestServ\",\"method\":\"\"}]},"
" {\"name\":[{\"service\":\"TestServ\"}]}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[1].name[0] "
"error:multiple method configs for path /TestServ/]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigs) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{}]},"
" {\"name\":[{}]}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[1].name[0] "
"error:duplicate default method config]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithNullService) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":null}]},"
" {\"name\":[{}]}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[1].name[0] "
"error:duplicate default method config]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithEmptyService) {
const char* test_json =
"{\"methodConfig\": ["
" {\"name\":[{\"service\":\"\"}]},"
" {\"name\":[{}]}"
"]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[1].name[0] "
"error:duplicate default method config]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, ValidMethodConfig) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
}
TEST_F(ServiceConfigTest, Parser1BasicTest1) {
const char* test_json = "{\"global_param\":5}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
EXPECT_EQ((static_cast<TestParsedConfig1*>(
(*service_config)->GetGlobalParsedConfig(0)))
->value(),
5);
EXPECT_EQ((*service_config)
->GetMethodParsedConfigVector(
grpc_slice_from_static_string("/TestServ/TestMethod")),
nullptr);
}
TEST_F(ServiceConfigTest, Parser1BasicTest2) {
const char* test_json = "{\"global_param\":1000}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
EXPECT_EQ((static_cast<TestParsedConfig1*>(
(*service_config)->GetGlobalParsedConfig(0)))
->value(),
1000);
}
TEST_F(ServiceConfigTest, Parser1DisabledViaChannelArg) {
const ChannelArgs args = ChannelArgs().Set(GRPC_ARG_DISABLE_PARSING, 1);
const char* test_json = "{\"global_param\":5}";
auto service_config = ServiceConfigImpl::Create(args, test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
EXPECT_EQ((*service_config)->GetGlobalParsedConfig(0), nullptr);
}
TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
const char* test_json = "{\"global_param\":[]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:global_param error:is not a number]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) {
const char* test_json = "{\"global_param\":-5}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:global_param error:failed to parse non-negative number]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, Parser2BasicTest) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
"\"method_param\":5}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->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) {
const ChannelArgs args = ChannelArgs().Set(GRPC_ARG_DISABLE_PARSING, 1);
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
"\"method_param\":5}]}";
auto service_config = ServiceConfigImpl::Create(args, test_json);
ASSERT_TRUE(service_config.ok()) << service_config.status();
const auto* vector_ptr =
(*service_config)
->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\":[]}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].method_param error:is not a number]")
<< service_config.status();
}
TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) {
const char* test_json =
"{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
"\"method_param\":-5}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].method_param "
"error:failed to parse non-negative number]")
<< service_config.status();
}
TEST(ServiceConfigParserTest, DoubleRegistration) {
CoreConfiguration::Reset();
ASSERT_DEATH_IF_SUPPORTED(
CoreConfiguration::WithSubstituteBuilder builder(
[](CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<TestParser1>());
builder->service_config_parser()->RegisterParser(
std::make_unique<TestParser1>());
}),
"test_parser_1.*already registered");
}
// 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 ChannelArgs& /*arg*/, const Json& /*json*/,
ValidationErrors* errors) override {
ValidationErrors::ScopedField field(errors, absl::StrCat(".", name_));
errors->AddError("method error");
return nullptr;
}
std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
const ChannelArgs& /*arg*/, const Json& /*json*/,
ValidationErrors* errors) override {
ValidationErrors::ScopedField field(errors, absl::StrCat(".", name_));
errors->AddError("global error");
return nullptr;
}
private:
absl::string_view name_;
};
// Test parsing with ErrorParsers which always add errors
class ErroredParsersScopingTest : public ::testing::Test {
protected:
void SetUp() override {
builder_ = std::make_unique<CoreConfiguration::WithSubstituteBuilder>(
[](CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<ErrorParser>("ep1"));
builder->service_config_parser()->RegisterParser(
std::make_unique<ErrorParser>("ep2"));
});
EXPECT_EQ(
CoreConfiguration::Get().service_config_parser().GetParserIndex("ep1"),
0);
EXPECT_EQ(
CoreConfiguration::Get().service_config_parser().GetParserIndex("ep2"),
1);
}
private:
std::unique_ptr<CoreConfiguration::WithSubstituteBuilder> builder_;
};
TEST_F(ErroredParsersScopingTest, GlobalParams) {
const char* test_json = "{}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:ep1 error:global error; field:ep2 error:global error]")
<< service_config.status();
}
TEST_F(ErroredParsersScopingTest, MethodParams) {
const char* test_json = "{\"methodConfig\": [{}]}";
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:ep1 error:global error; "
"field:ep2 error:global error; "
"field:methodConfig[0].ep1 error:method error; "
"field:methodConfig[0].ep2 error:method error]")
<< service_config.status();
}
} // 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;
}

@ -37,7 +37,7 @@
#include <grpcpp/impl/codegen/config_protobuf.h> #include <grpcpp/impl/codegen/config_protobuf.h>
#include "src/core/ext/filters/fault_injection/fault_injection_filter.h" #include "src/core/ext/filters/fault_injection/fault_injection_filter.h"
#include "src/core/ext/filters/fault_injection/service_config_parser.h" #include "src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h"
#include "src/core/ext/filters/rbac/rbac_filter.h" #include "src/core/ext/filters/rbac/rbac_filter.h"
#include "src/core/ext/filters/rbac/rbac_service_config_parser.h" #include "src/core/ext/filters/rbac/rbac_service_config_parser.h"
#include "src/proto/grpc/testing/xds/v3/address.pb.h" #include "src/proto/grpc/testing/xds/v3/address.pb.h"
@ -693,7 +693,7 @@ TEST_P(XdsRbacFilterConfigTest, AllPermissionTypes) {
"\"ignoreCase\":false,\"safeRegex\":{\"regex\":\"regex_match\"}}}}," "\"ignoreCase\":false,\"safeRegex\":{\"regex\":\"regex_match\"}}}},"
// destination IP match with prefix len // destination IP match with prefix len
"{\"destinationIp\":{" "{\"destinationIp\":{"
"\"addressPrefix\":\"127.0.0\",\"prefixLen\":{\"value\":24}}}," "\"addressPrefix\":\"127.0.0\",\"prefixLen\":24}},"
// destination IP match // destination IP match
"{\"destinationIp\":{\"addressPrefix\":\"10.0.0\"}}," "{\"destinationIp\":{\"addressPrefix\":\"10.0.0\"}},"
// destination port match // destination port match

@ -577,7 +577,7 @@ current_test_subprocess = subprocess.Popen([
'--do_ordered_address_comparison', 'False', '--do_ordered_address_comparison', 'False',
'--expected_addrs', '1.2.3.4:443,False', '--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '', '--expected_chosen_service_config', '',
'--expected_service_config_error', 'field:waitForReady error:Type should be true/false', '--expected_service_config_error', 'field:methodConfig[0].waitForReady error:is not a boolean',
'--expected_lb_policy', '', '--expected_lb_policy', '',
'--enable_srv_queries', 'True', '--enable_srv_queries', 'True',
'--enable_txt_queries', 'True', '--enable_txt_queries', 'True',
@ -613,7 +613,7 @@ current_test_subprocess = subprocess.Popen([
'--do_ordered_address_comparison', 'False', '--do_ordered_address_comparison', 'False',
'--expected_addrs', '1.2.3.4:443,False', '--expected_addrs', '1.2.3.4:443,False',
'--expected_chosen_service_config', '', '--expected_chosen_service_config', '',
'--expected_service_config_error', 'field:loadBalancingPolicy error:type should be string', '--expected_service_config_error', 'field:loadBalancingPolicy error:is not a string',
'--expected_lb_policy', '', '--expected_lb_policy', '',
'--enable_srv_queries', 'True', '--enable_srv_queries', 'True',
'--enable_txt_queries', 'True', '--enable_txt_queries', 'True',

@ -435,7 +435,7 @@ resolver_component_tests:
- {address: '1.2.3.4:443', is_balancer: false} - {address: '1.2.3.4:443', is_balancer: false}
do_ordered_address_comparison: false do_ordered_address_comparison: false
expected_chosen_service_config: null expected_chosen_service_config: null
expected_service_config_error: 'field:waitForReady error:Type should be true/false' expected_service_config_error: 'field:methodConfig[0].waitForReady error:is not a boolean'
expected_lb_policy: null expected_lb_policy: null
enable_srv_queries: true enable_srv_queries: true
enable_txt_queries: true enable_txt_queries: true
@ -465,7 +465,7 @@ resolver_component_tests:
- {address: '1.2.3.4:443', is_balancer: false} - {address: '1.2.3.4:443', is_balancer: false}
do_ordered_address_comparison: false do_ordered_address_comparison: false
expected_chosen_service_config: null expected_chosen_service_config: null
expected_service_config_error: 'field:loadBalancingPolicy error:type should be string' expected_service_config_error: 'field:loadBalancingPolicy error:is not a string'
expected_lb_policy: null expected_lb_policy: null
enable_srv_queries: true enable_srv_queries: true
enable_txt_queries: true enable_txt_queries: true

@ -1074,6 +1074,8 @@ src/core/ext/filters/client_channel/client_channel_channelz.h \
src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_factory.h \ src/core/ext/filters/client_channel/client_channel_factory.h \
src/core/ext/filters/client_channel/client_channel_plugin.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/client_channel_service_config.cc \
src/core/ext/filters/client_channel/client_channel_service_config.h \
src/core/ext/filters/client_channel/config_selector.cc \ src/core/ext/filters/client_channel/config_selector.cc \
src/core/ext/filters/client_channel/config_selector.h \ src/core/ext/filters/client_channel/config_selector.h \
src/core/ext/filters/client_channel/connector.h \ src/core/ext/filters/client_channel/connector.h \
@ -1142,8 +1144,6 @@ src/core/ext/filters/client_channel/resolver/polling_resolver.h \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \
src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/resolver_result_parsing.h \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_filter.h \ src/core/ext/filters/client_channel/retry_filter.h \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \
@ -1162,8 +1162,8 @@ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/deadline/deadline_filter.h \ src/core/ext/filters/deadline/deadline_filter.h \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.h \ src/core/ext/filters/fault_injection/fault_injection_filter.h \
src/core/ext/filters/fault_injection/service_config_parser.cc \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/fault_injection/service_config_parser.h \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h \
src/core/ext/filters/http/client/http_client_filter.cc \ src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client/http_client_filter.h \ src/core/ext/filters/http/client/http_client_filter.h \
src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/client_authority_filter.cc \
@ -2249,6 +2249,7 @@ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/iomgr/wakeup_fd_posix.h \ src/core/lib/iomgr/wakeup_fd_posix.h \
src/core/lib/json/json.h \ src/core/lib/json/json.h \
src/core/lib/json/json_args.h \ src/core/lib/json/json_args.h \
src/core/lib/json/json_channel_args.h \
src/core/lib/json/json_object_loader.cc \ src/core/lib/json/json_object_loader.cc \
src/core/lib/json/json_object_loader.h \ src/core/lib/json/json_object_loader.h \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \

@ -890,6 +890,8 @@ src/core/ext/filters/client_channel/client_channel_channelz.h \
src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \
src/core/ext/filters/client_channel/client_channel_factory.h \ src/core/ext/filters/client_channel/client_channel_factory.h \
src/core/ext/filters/client_channel/client_channel_plugin.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \
src/core/ext/filters/client_channel/client_channel_service_config.cc \
src/core/ext/filters/client_channel/client_channel_service_config.h \
src/core/ext/filters/client_channel/config_selector.cc \ src/core/ext/filters/client_channel/config_selector.cc \
src/core/ext/filters/client_channel/config_selector.h \ src/core/ext/filters/client_channel/config_selector.h \
src/core/ext/filters/client_channel/connector.h \ src/core/ext/filters/client_channel/connector.h \
@ -962,8 +964,6 @@ src/core/ext/filters/client_channel/resolver/sockaddr/README.md \
src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \ src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc \
src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \ src/core/ext/filters/client_channel/resolver/xds/xds_resolver.h \
src/core/ext/filters/client_channel/resolver_result_parsing.cc \
src/core/ext/filters/client_channel/resolver_result_parsing.h \
src/core/ext/filters/client_channel/retry_filter.cc \ src/core/ext/filters/client_channel/retry_filter.cc \
src/core/ext/filters/client_channel/retry_filter.h \ src/core/ext/filters/client_channel/retry_filter.h \
src/core/ext/filters/client_channel/retry_service_config.cc \ src/core/ext/filters/client_channel/retry_service_config.cc \
@ -982,8 +982,8 @@ src/core/ext/filters/deadline/deadline_filter.cc \
src/core/ext/filters/deadline/deadline_filter.h \ src/core/ext/filters/deadline/deadline_filter.h \
src/core/ext/filters/fault_injection/fault_injection_filter.cc \ src/core/ext/filters/fault_injection/fault_injection_filter.cc \
src/core/ext/filters/fault_injection/fault_injection_filter.h \ src/core/ext/filters/fault_injection/fault_injection_filter.h \
src/core/ext/filters/fault_injection/service_config_parser.cc \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
src/core/ext/filters/fault_injection/service_config_parser.h \ src/core/ext/filters/fault_injection/fault_injection_service_config_parser.h \
src/core/ext/filters/http/client/http_client_filter.cc \ src/core/ext/filters/http/client/http_client_filter.cc \
src/core/ext/filters/http/client/http_client_filter.h \ src/core/ext/filters/http/client/http_client_filter.h \
src/core/ext/filters/http/client_authority_filter.cc \ src/core/ext/filters/http/client_authority_filter.cc \
@ -2040,6 +2040,7 @@ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/iomgr/wakeup_fd_posix.h \ src/core/lib/iomgr/wakeup_fd_posix.h \
src/core/lib/json/json.h \ src/core/lib/json/json.h \
src/core/lib/json/json_args.h \ src/core/lib/json/json_args.h \
src/core/lib/json/json_channel_args.h \
src/core/lib/json/json_object_loader.cc \ src/core/lib/json/json_object_loader.cc \
src/core/lib/json/json_object_loader.h \ src/core/lib/json/json_object_loader.h \
src/core/lib/json/json_reader.cc \ src/core/lib/json/json_reader.cc \

@ -1943,6 +1943,30 @@
], ],
"uses_polling": true "uses_polling": true
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "client_channel_service_config_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,
@ -4645,6 +4669,30 @@
], ],
"uses_polling": false "uses_polling": false
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "message_size_service_config_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,
@ -5737,6 +5785,30 @@
], ],
"uses_polling": false "uses_polling": false
}, },
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "retry_service_config_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{ {
"args": [], "args": [],
"benchmark": false, "benchmark": false,

Loading…
Cancel
Save