Revert "Revert "service config: use new JSON API (#30467)" (#31485)" (#31486)

This reverts commit 008661a5d6.
pull/31496/head
Mark D. Roth 2 years ago committed by GitHub
parent e60140676a
commit 49da06c3a1
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

@ -2504,9 +2504,9 @@ grpc_cc_library(
"//src/core:lib/service_config/service_config_impl.h",
],
external_deps = [
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/types:optional",
],
language = "c++",
visibility = ["@grpc:client_channel"],
@ -2517,9 +2517,12 @@ grpc_cc_library(
"//src/core:channel_args",
"//src/core:grpc_service_config",
"//src/core:json",
"//src/core:json_args",
"//src/core:json_object_loader",
"//src/core:service_config_parser",
"//src/core:slice",
"//src/core:slice_refcount",
"//src/core:validation_errors",
],
)
@ -2590,6 +2593,7 @@ grpc_cc_library(
"//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_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/dynamic_filters.cc",
"//src/core:ext/filters/client_channel/global_subchannel_pool.cc",
@ -2598,7 +2602,6 @@ grpc_cc_library(
"//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/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_service_config.cc",
"//src/core:ext/filters/client_channel/retry_throttle.cc",
@ -2613,6 +2616,7 @@ grpc_cc_library(
"//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_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/connector.h",
"//src/core:ext/filters/client_channel/dynamic_filters.h",
@ -2622,7 +2626,6 @@ grpc_cc_library(
"//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/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_service_config.h",
"//src/core:ext/filters/client_channel/retry_throttle.h",
@ -2681,7 +2684,9 @@ grpc_cc_library(
"//src/core:init_internally",
"//src/core:iomgr_fwd",
"//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_registry",
"//src/core:memory_quota",
@ -2702,6 +2707,7 @@ grpc_cc_library(
"//src/core:transport_fwd",
"//src/core:unique_type_name",
"//src/core:useful",
"//src/core:validation_errors",
],
)

119
CMakeLists.txt generated

@ -869,6 +869,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx client_auth_filter_test)
add_dependencies(buildtests_cxx client_authority_filter_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)
add_dependencies(buildtests_cxx client_channel_stress_test)
endif()
@ -1032,6 +1033,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx memory_quota_test)
add_dependencies(buildtests_cxx message_allocator_end2end_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 miscompile_with_no_unique_address_test)
add_dependencies(buildtests_cxx mock_stream_test)
@ -1097,6 +1099,7 @@ if(gRPC_BUILD_TESTS)
endif()
add_dependencies(buildtests_cxx resolve_address_using_native_resolver_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 rls_end2end_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_factory.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/dynamic_filters.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/sockaddr/sockaddr_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_service_config.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/deadline/deadline_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_authority_filter.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_factory.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/dynamic_filters.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/polling_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_service_config.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/deadline/deadline_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_authority_filter.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/json/json_object_loader.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/load_balancing/lb_policy.cc
src/core/lib/load_balancing/lb_policy_registry.cc
@ -7802,6 +7804,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()
if(gRPC_BUILD_TESTS)
if(_gRPC_PLATFORM_LINUX OR _gRPC_PLATFORM_MAC OR _gRPC_PLATFORM_POSIX)
@ -13584,6 +13621,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()
if(gRPC_BUILD_TESTS)
@ -15707,6 +15779,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()
if(gRPC_BUILD_TESTS)
@ -16711,7 +16818,7 @@ endif()
if(gRPC_BUILD_TESTS)
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/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_factory.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/dynamic_filters.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/sockaddr/sockaddr_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_service_config.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/deadline/deadline_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_authority_filter.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_factory.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/dynamic_filters.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/polling_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_service_config.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/deadline/deadline_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_authority_filter.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/json/json_object_loader.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/load_balancing/lb_policy.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_transport_grpc.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/security/authorization/grpc_authorization_engine.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_channelz.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/connector.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/polling_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_service_config.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/deadline/deadline_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_authority_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/json/json.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_util.h
- src/core/lib/load_balancing/lb_policy.h
@ -1050,6 +1051,7 @@ libs:
- 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_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/dynamic_filters.cc
- src/core/ext/filters/client_channel/global_subchannel_pool.cc
@ -1091,7 +1093,6 @@ libs:
- 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/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_service_config.cc
- src/core/ext/filters/client_channel/retry_throttle.cc
@ -1101,7 +1102,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.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/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_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc
@ -1888,6 +1889,7 @@ libs:
- 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_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/connector.h
- src/core/ext/filters/client_channel/dynamic_filters.h
@ -1912,7 +1914,6 @@ libs:
- 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/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_service_config.h
- src/core/ext/filters/client_channel/retry_throttle.h
@ -1922,7 +1923,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.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/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_authority_filter.h
- src/core/ext/filters/http/message_compress/message_compress_filter.h
@ -2127,8 +2128,8 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.h
- src/core/lib/json/json.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_util.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_registry.h
@ -2256,6 +2257,7 @@ libs:
- 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_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/dynamic_filters.cc
- src/core/ext/filters/client_channel/global_subchannel_pool.cc
@ -2289,7 +2291,6 @@ libs:
- 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/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_service_config.cc
- src/core/ext/filters/client_channel/retry_throttle.cc
@ -2299,7 +2300,7 @@ libs:
- src/core/ext/filters/client_channel/subchannel_stream_client.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/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_authority_filter.cc
- src/core/ext/filters/http/http_filters_plugin.cc
@ -2488,7 +2489,6 @@ libs:
- src/core/lib/iomgr/wakeup_fd_posix.cc
- src/core/lib/json/json_object_loader.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/load_balancing/lb_policy.cc
- src/core/lib/load_balancing/lb_policy_registry.cc
@ -5172,6 +5172,15 @@ targets:
- test/cpp/end2end/test_service_impl.cc
deps:
- 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
gtest: true
build: test
@ -8027,6 +8036,15 @@ targets:
deps:
- grpc_test_util
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
gtest: true
build: test
@ -9050,6 +9068,15 @@ targets:
deps:
- grpc_test_util_unsecure
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
gtest: true
build: test
@ -9472,7 +9499,7 @@ targets:
language: c++
headers: []
src:
- test/core/client_channel/service_config_test.cc
- test/core/service_config/service_config_test.cc
deps:
- grpc_test_util
- 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_factory.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/dynamic_filters.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/sockaddr/sockaddr_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_service_config.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/deadline/deadline_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_authority_filter.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_factory.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\\dynamic_filters.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\\sockaddr\\sockaddr_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_service_config.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\\deadline\\deadline_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_authority_filter.cc " +
"src\\core\\ext\\filters\\http\\http_filters_plugin.cc " +

10
gRPC-C++.podspec generated

@ -232,6 +232,7 @@ Pod::Spec.new do |s|
'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_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/connector.h',
'src/core/ext/filters/client_channel/dynamic_filters.h',
@ -259,7 +260,6 @@ Pod::Spec.new do |s|
'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/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_service_config.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
@ -269,7 +269,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel_stream_client.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/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_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@ -833,6 +833,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.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_util.h',
'src/core/lib/load_balancing/lb_policy.h',
@ -1128,6 +1129,7 @@ Pod::Spec.new do |s|
'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_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/connector.h',
'src/core/ext/filters/client_channel/dynamic_filters.h',
@ -1155,7 +1157,6 @@ Pod::Spec.new do |s|
'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/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_service_config.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
@ -1165,7 +1166,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel_stream_client.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/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_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@ -1711,6 +1712,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.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_util.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.h',
'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.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/xds/xds_resolver.cc',
'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.h',
'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/fault_injection/fault_injection_filter.cc',
'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/service_config_parser.h',
'src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc',
'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.h',
'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/json/json.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.h',
'src/core/lib/json/json_reader.cc',
@ -1785,6 +1786,7 @@ Pod::Spec.new do |s|
'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_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/connector.h',
'src/core/ext/filters/client_channel/dynamic_filters.h',
@ -1812,7 +1814,6 @@ Pod::Spec.new do |s|
'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/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_service_config.h',
'src/core/ext/filters/client_channel/retry_throttle.h',
@ -1822,7 +1823,7 @@ Pod::Spec.new do |s|
'src/core/ext/filters/client_channel/subchannel_stream_client.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/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_authority_filter.h',
'src/core/ext/filters/http/message_compress/message_compress_filter.h',
@ -2348,6 +2349,7 @@ Pod::Spec.new do |s|
'src/core/lib/iomgr/wakeup_fd_posix.h',
'src/core/lib/json/json.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_util.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.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_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.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/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_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.h )
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/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/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.cc )
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.h )
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/json/json.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.h )
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_factory.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/dynamic_filters.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/sockaddr/sockaddr_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_service_config.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/deadline/deadline_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_authority_filter.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_factory.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/dynamic_filters.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/polling_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_service_config.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/deadline/deadline_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_authority_filter.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/json/json_object_loader.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/load_balancing/lb_policy.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.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_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.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/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_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.h" 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/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/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.cc" 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.h" 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/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_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.h" role="src" />
<file baseinstalldir="/" name="src/core/lib/json/json_reader.cc" role="src" />

@ -2070,15 +2070,12 @@ grpc_cc_library(
hdrs = [
"lib/service_config/service_config_parser.h",
],
external_deps = [
"absl/status",
"absl/status:statusor",
"absl/strings",
],
external_deps = ["absl/strings"],
language = "c++",
deps = [
"channel_args",
"json",
"validation_errors",
"//:gpr",
],
)
@ -3068,7 +3065,6 @@ grpc_cc_library(
],
external_deps = [
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/strings:str_format",
"absl/types:optional",
@ -3082,9 +3078,12 @@ grpc_cc_library(
"closure",
"grpc_service_config",
"json",
"json_args",
"json_object_loader",
"service_config_parser",
"slice_buffer",
"status_helper",
"validation_errors",
"//:channel_stack_builder",
"//:config",
"//:debug_location",
@ -3098,11 +3097,11 @@ grpc_cc_library(
name = "grpc_fault_injection_filter",
srcs = [
"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 = [
"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 = [
"absl/base:core_headers",
@ -3119,12 +3118,13 @@ grpc_cc_library(
"context",
"grpc_service_config",
"json",
"json_util",
"json_args",
"json_object_loader",
"service_config_parser",
"sleep",
"status_helper",
"time",
"try_seq",
"validation_errors",
"//:config",
"//:gpr",
"//:grpc_base",
@ -3147,7 +3147,6 @@ grpc_cc_library(
"absl/status",
"absl/status:statusor",
"absl/strings",
"absl/strings:str_format",
"absl/types:optional",
],
language = "c++",
@ -3160,10 +3159,12 @@ grpc_cc_library(
"grpc_rbac_engine",
"grpc_service_config",
"json",
"json_util",
"json_args",
"json_object_loader",
"service_config_parser",
"status_helper",
"transport_fwd",
"validation_errors",
"//:config",
"//:debug_location",
"//:gpr",

@ -47,12 +47,12 @@
#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/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/dynamic_filters.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/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/subchannel.h"
#include "src/core/ext/filters/client_channel/subchannel_interface_internal.h"

@ -19,7 +19,7 @@
#include <grpc/support/port_platform.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/lib/channel/channel_stack_builder.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.
//
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_RESOLVER_RESULT_PARSING_H
#define 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_CLIENT_CHANNEL_SERVICE_CONFIG_H
#include <grpc/support/port_platform.h>
@ -23,9 +23,7 @@
#include <memory>
#include <string>
#include <utility>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@ -33,7 +31,10 @@
#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/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/load_balancing/lb_policy.h"
#include "src/core/lib/service_config/service_config_parser.h"
@ -43,14 +44,6 @@ namespace internal {
class ClientChannelGlobalParsedConfig
: public ServiceConfigParser::ParsedConfig {
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 {
return parsed_lb_config_;
}
@ -60,26 +53,34 @@ class ClientChannelGlobalParsedConfig
}
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:
struct HealthCheckConfig {
absl::optional<std::string> service_name;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
};
RefCountedPtr<LoadBalancingPolicy::Config> parsed_lb_config_;
std::string parsed_deprecated_lb_policy_;
absl::optional<std::string> health_check_service_name_;
HealthCheckConfig health_check_config_;
};
class ClientChannelMethodParsedConfig
: public ServiceConfigParser::ParsedConfig {
public:
ClientChannelMethodParsedConfig(Duration timeout,
const absl::optional<bool>& wait_for_ready)
: timeout_(timeout), wait_for_ready_(wait_for_ready) {}
Duration timeout() const { return timeout_; }
absl::optional<bool> wait_for_ready() const { return wait_for_ready_; }
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
private:
Duration timeout_;
absl::optional<bool> wait_for_ready_;
@ -89,11 +90,13 @@ class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
public:
absl::string_view name() const override { return parser_name(); }
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
ParseGlobalParams(const ChannelArgs& /*args*/, const Json& json) override;
std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
const ChannelArgs& /*args*/, const Json& json,
ValidationErrors* errors) override;
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
ParsePerMethodParams(const ChannelArgs& /*args*/, const Json& json) override;
std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
const ChannelArgs& /*args*/, const Json& json,
ValidationErrors* errors) override;
static size_t ParserIndex();
static void Register(CoreConfiguration::Builder* builder);
@ -105,4 +108,4 @@ class ClientChannelServiceConfigParser : public ServiceConfigParser::Parser {
} // namespace internal
} // 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()) {
ValidationErrors::ScopedField field(errors,
".routeLookupChannelServiceConfig");
grpc_error_handle child_error;
rls_channel_service_config_ = it->second.Dump();
auto service_config = MakeRefCounted<ServiceConfigImpl>(
ChannelArgs(), rls_channel_service_config_, it->second, &child_error);
if (!child_error.ok()) {
errors->AddError(StatusToString(child_error));
}
// Don't need to save the result here, just need the errors (if any).
ServiceConfigImpl::Create(ChannelArgs(), it->second, errors);
}
// 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 <stdio.h>
#include <string.h>
#include <algorithm>
#include <cstdint>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/types/optional.h"
@ -38,10 +35,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/status_util.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/lib/gpr/string.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/json/json_channel_args.h"
// As per the retry design, we do not allow more than 5 retry attempts.
#define MAX_MAX_RETRY_ATTEMPTS 5
@ -49,271 +43,240 @@
namespace grpc_core {
namespace internal {
size_t RetryServiceConfigParser::ParserIndex() {
return CoreConfiguration::Get().service_config_parser().GetParserIndex(
parser_name());
}
//
// RetryGlobalConfig
//
void RetryServiceConfigParser::Register(CoreConfiguration::Builder* builder) {
builder->service_config_parser()->RegisterParser(
std::make_unique<RetryServiceConfigParser>());
const JsonLoaderInterface* RetryGlobalConfig::JsonLoader(const JsonArgs&) {
// Note: Both fields require custom processing, so they're handled in
// JsonPostLoad() instead.
static const auto* loader = JsonObjectLoader<RetryGlobalConfig>().Finish();
return loader;
}
namespace {
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;
void RetryGlobalConfig::JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors) {
// Parse maxTokens.
auto it = json.object_value().find("maxTokens");
if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:maxTokens error:Not found"));
} else if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:maxTokens error:Type should be "
"number"));
auto max_tokens = LoadJsonObjectField<uint32_t>(json.object_value(), args,
"maxTokens", errors);
if (max_tokens.has_value()) {
ValidationErrors::ScopedField field(errors, ".maxTokens");
if (*max_tokens == 0) {
errors->AddError("must be greater than 0");
} else {
*max_milli_tokens =
gpr_parse_nonnegative_int(it->second.string_value().c_str()) * 1000;
if (*max_milli_tokens <= 0) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:maxTokens error:should be "
"greater than zero"));
// Multiply by 1000 to represent as milli-tokens.
max_milli_tokens_ = static_cast<uintptr_t>(*max_tokens) * 1000;
}
}
// 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()) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:tokenRatio error:Not found"));
} else if (it->second.type() != Json::Type::NUMBER) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:tokenRatio error:type should be "
"number"));
} else {
// We support up to 3 decimal digits.
size_t whole_len = it->second.string_value().size();
const char* value = it->second.string_value().c_str();
errors->AddError("field not present");
return;
}
if (it->second.type() != Json::Type::NUMBER &&
it->second.type() != Json::Type::STRING) {
errors->AddError("is not a number");
return;
}
absl::string_view buf = it->second.string_value();
uint32_t multiplier = 1;
uint32_t decimal_value = 0;
const char* decimal_point = strchr(value, '.');
if (decimal_point != nullptr) {
whole_len = static_cast<size_t>(decimal_point - value);
auto decimal_point = buf.find('.');
if (decimal_point != absl::string_view::npos) {
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;
size_t decimal_len = strlen(decimal_point + 1);
if (decimal_len > 3) decimal_len = 3;
if (!gpr_parse_bytes_to_uint32(decimal_point + 1, decimal_len,
&decimal_value)) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:tokenRatio error:Failed "
"parsing"));
return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
if (after_decimal.length() > 3) after_decimal = after_decimal.substr(0, 3);
// Parse decimal value.
if (!absl::SimpleAtoi(after_decimal, &decimal_value)) {
errors->AddError("could not parse as a number");
return;
}
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_value *= decimal_multiplier;
}
uint32_t whole_value;
if (!gpr_parse_bytes_to_uint32(value, whole_len, &whole_value)) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:tokenRatio error:Failed "
"parsing"));
return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
if (!absl::SimpleAtoi(buf, &whole_value)) {
errors->AddError("could not parse as a number");
return;
}
*milli_token_ratio =
milli_token_ratio_ =
static_cast<int>((whole_value * multiplier) + decimal_value);
if (*milli_token_ratio <= 0) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryThrottling field:tokenRatio error:value should "
"be greater than 0"));
}
if (milli_token_ratio_ <= 0) {
errors->AddError("must be greater than 0");
}
return GRPC_ERROR_CREATE_FROM_VECTOR("retryThrottling", &error_list);
}
} // namespace
//
// RetryMethodConfig
//
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
RetryServiceConfigParser::ParseGlobalParams(const ChannelArgs& /*args*/,
const Json& json) {
auto it = json.object_value().find("retryThrottling");
if (it == json.object_value().end()) return nullptr;
intptr_t max_milli_tokens = 0;
intptr_t milli_token_ratio = 0;
grpc_error_handle error =
ParseRetryThrottling(it->second, &max_milli_tokens, &milli_token_ratio);
if (!error.ok()) {
absl::Status status = absl::InvalidArgumentError(absl::StrCat(
"error parsing retry global parameters: ", StatusToString(error)));
return status;
}
return std::make_unique<RetryGlobalConfig>(max_milli_tokens,
milli_token_ratio);
const JsonLoaderInterface* RetryMethodConfig::JsonLoader(const JsonArgs&) {
static const auto* loader =
JsonObjectLoader<RetryMethodConfig>()
// Note: The "retryableStatusCodes" field requires custom parsing,
// so it's handled in JsonPostLoad() instead.
.Field("maxAttempts", &RetryMethodConfig::max_attempts_)
.Field("initialBackoff", &RetryMethodConfig::initial_backoff_)
.Field("maxBackoff", &RetryMethodConfig::max_backoff_)
.Field("backoffMultiplier", &RetryMethodConfig::backoff_multiplier_)
.OptionalField("perAttemptRecvTimeout",
&RetryMethodConfig::per_attempt_recv_timeout_,
GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING)
.Finish();
return loader;
}
namespace {
grpc_error_handle ParseRetryPolicy(
const ChannelArgs& args, const Json& json, int* max_attempts,
Duration* initial_backoff, Duration* max_backoff, float* backoff_multiplier,
StatusCodeSet* retryable_status_codes,
absl::optional<Duration>* per_attempt_recv_timeout) {
if (json.type() != Json::Type::OBJECT) {
return GRPC_ERROR_CREATE(
"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) {
void RetryMethodConfig::JsonPostLoad(const Json& json, const JsonArgs& args,
ValidationErrors* errors) {
// Validate maxAttempts.
{
ValidationErrors::ScopedField field(errors, ".maxAttempts");
if (!errors->FieldHasErrors()) {
if (max_attempts_ <= 1) {
errors->AddError("must be at least 2");
} else if (max_attempts_ > MAX_MAX_RETRY_ATTEMPTS) {
gpr_log(GPR_ERROR,
"service config: clamped retryPolicy.maxAttempts at %d",
MAX_MAX_RETRY_ATTEMPTS);
*max_attempts = MAX_MAX_RETRY_ATTEMPTS;
max_attempts_ = MAX_MAX_RETRY_ATTEMPTS;
}
}
}
// Parse initialBackoff.
if (ParseJsonObjectFieldAsDuration(json.object_value(), "initialBackoff",
initial_backoff, &error_list) &&
*initial_backoff == Duration::Zero()) {
error_list.push_back(
GRPC_ERROR_CREATE("field:initialBackoff error:must be greater than 0"));
// Validate initialBackoff.
{
ValidationErrors::ScopedField field(errors, ".initialBackoff");
if (!errors->FieldHasErrors() && initial_backoff_ == Duration::Zero()) {
errors->AddError("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.
it = json.object_value().find("backoffMultiplier");
if (it == json.object_value().end()) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:backoffMultiplier error:required field missing"));
} 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 maxBackoff.
{
ValidationErrors::ScopedField field(errors, ".maxBackoff");
if (!errors->FieldHasErrors() && max_backoff_ == Duration::Zero()) {
errors->AddError("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;
if (!grpc_status_code_from_string(element.string_value().c_str(),
if (!grpc_status_code_from_string((*status_code_list)[i].c_str(),
&status)) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryableStatusCodes error:failed to parse status code"));
continue;
}
retryable_status_codes->Add(status);
errors->AddError("failed to parse status code");
} else {
retryable_status_codes_.Add(status);
}
}
}
// Parse perAttemptRecvTimeout.
if (args.GetBool(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING).value_or(false)) {
it = json.object_value().find("perAttemptRecvTimeout");
if (it != json.object_value().end()) {
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;
// Validate perAttemptRecvTimeout.
if (args.IsEnabled(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING)) {
if (per_attempt_recv_timeout_.has_value()) {
ValidationErrors::ScopedField field(errors, ".perAttemptRecvTimeout");
// TODO(roth): As part of implementing hedging, relax this check such
// that we allow a value of 0 if a hedging policy is specified.
if (per_attempt_recv_timeout_value == Duration::Zero()) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:perAttemptRecvTimeout error:must be greater than 0"));
}
if (!errors->FieldHasErrors() &&
*per_attempt_recv_timeout_ == Duration::Zero()) {
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
// non-empty.
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryableStatusCodes error:must be non-empty if "
"perAttemptRecvTimeout not present"));
ValidationErrors::ScopedField field(errors, ".retryableStatusCodes");
if (!errors->FieldHasErrors()) {
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
// retryableStatusCodes unset should be different.
if (retryable_status_codes->Empty()) {
error_list.push_back(GRPC_ERROR_CREATE(
"field:retryableStatusCodes error:must be non-empty"));
ValidationErrors::ScopedField field(errors, ".retryableStatusCodes");
if (!errors->FieldHasErrors()) {
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
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
std::unique_ptr<ServiceConfigParser::ParsedConfig>
RetryServiceConfigParser::ParsePerMethodParams(const ChannelArgs& args,
const Json& json) {
// Parse retry policy.
auto it = json.object_value().find("retryPolicy");
if (it == json.object_value().end()) return nullptr;
int max_attempts = 0;
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);
const Json& json,
ValidationErrors* errors) {
auto method_params =
LoadFromJson<MethodConfig>(json, JsonChannelArgs(args), errors);
return std::move(method_params.retry_policy);
}
} // namespace internal

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

@ -34,22 +34,22 @@ namespace internal {
//
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)
: max_milli_tokens_(max_milli_tokens),
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
// the token count by scaling proportionately to the old data. This
// ensures that if we're already throttling retries on the old scale,
// we will start out doing the same thing on the new one.
if (old_throttle_data != nullptr) {
double token_fraction =
static_cast<intptr_t>(
static_cast<uintptr_t>(
gpr_atm_acq_load(&old_throttle_data->milli_tokens_)) /
static_cast<double>(old_throttle_data->max_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));
// 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;
GetReplacementThrottleDataIfNeeded(&throttle_data);
// We decrement milli_tokens by 1000 (1 token) for each failure.
const intptr_t new_value =
static_cast<intptr_t>(gpr_atm_no_barrier_clamped_add(
const uintptr_t new_value =
static_cast<uintptr_t>(gpr_atm_no_barrier_clamped_add(
&throttle_data->milli_tokens_, static_cast<gpr_atm>(-1000),
static_cast<gpr_atm>(0),
static_cast<gpr_atm>(throttle_data->max_milli_tokens_)));
@ -118,8 +118,8 @@ ServerRetryThrottleMap* ServerRetryThrottleMap::Get() {
}
RefCountedPtr<ServerRetryThrottleData> ServerRetryThrottleMap::GetDataForServer(
const std::string& server_name, intptr_t max_milli_tokens,
intptr_t milli_token_ratio) {
const std::string& server_name, uintptr_t max_milli_tokens,
uintptr_t milli_token_ratio) {
MutexLock lock(&mu_);
auto it = map_.find(server_name);
ServerRetryThrottleData* throttle_data =

@ -40,7 +40,8 @@ namespace internal {
/// Tracks retry throttling data for an individual server name.
class ServerRetryThrottleData : public RefCounted<ServerRetryThrottleData> {
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() override;
@ -50,15 +51,15 @@ class ServerRetryThrottleData : public RefCounted<ServerRetryThrottleData> {
/// Records a success.
void RecordSuccess();
intptr_t max_milli_tokens() const { return max_milli_tokens_; }
intptr_t milli_token_ratio() const { return milli_token_ratio_; }
uintptr_t max_milli_tokens() const { return max_milli_tokens_; }
uintptr_t milli_token_ratio() const { return milli_token_ratio_; }
private:
void GetReplacementThrottleDataIfNeeded(
ServerRetryThrottleData** throttle_data);
const intptr_t max_milli_tokens_;
const intptr_t milli_token_ratio_;
const uintptr_t max_milli_tokens_;
const uintptr_t milli_token_ratio_;
gpr_atm milli_tokens_;
// A pointer to the replacement for this ServerRetryThrottleData entry.
// 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
/// needed.
RefCountedPtr<ServerRetryThrottleData> GetDataForServer(
const std::string& server_name, intptr_t max_milli_tokens,
intptr_t milli_token_ratio);
const std::string& server_name, uintptr_t max_milli_tokens,
uintptr_t milli_token_ratio);
private:
using StringToDataMap =

@ -35,7 +35,7 @@
#include <grpc/status.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/context.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.
//
#ifndef GRPC_CORE_EXT_FILTERS_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
#define 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_FAULT_INJECTION_SERVICE_CONFIG_PARSER_H
#include <grpc/support/port_platform.h>
@ -25,10 +25,8 @@
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include <grpc/status.h>
@ -36,7 +34,10 @@
#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/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_parser.h"
// Channel arg key for enabling parsing fault injection via method config.
@ -50,7 +51,7 @@ class FaultInjectionMethodParsedConfig
public:
struct FaultInjectionPolicy {
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_percentage_header;
uint32_t abort_percentage_numerator = 0;
@ -64,11 +65,11 @@ class FaultInjectionMethodParsedConfig
// By default, the max allowed active faults are unlimited.
uint32_t max_faults = std::numeric_limits<uint32_t>::max();
};
explicit FaultInjectionMethodParsedConfig(
std::vector<FaultInjectionPolicy> fault_injection_policies)
: fault_injection_policies_(std::move(fault_injection_policies)) {}
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
void JsonPostLoad(const Json& json, const JsonArgs&,
ValidationErrors* errors);
};
// Returns the fault injection policy at certain index.
// There might be multiple fault injection policies functioning at the same
@ -83,6 +84,8 @@ class FaultInjectionMethodParsedConfig
return &fault_injection_policies_[index];
}
static const JsonLoaderInterface* JsonLoader(const JsonArgs&);
private:
std::vector<FaultInjectionPolicy> fault_injection_policies_;
};
@ -92,8 +95,9 @@ class FaultInjectionServiceConfigParser final
public:
absl::string_view name() const override { return parser_name(); }
// Parses the per-method service config for fault injection filter.
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
ParsePerMethodParams(const ChannelArgs& args, const Json& json) override;
std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
const ChannelArgs& args, const Json& json,
ValidationErrors* errors) override;
// Returns the parser index for FaultInjectionServiceConfigParser.
static size_t ParserIndex();
// Registers FaultInjectionServiceConfigParser to ServiceConfigParser.
@ -105,4 +109,4 @@ class FaultInjectionServiceConfigParser final
} // 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 <stdint.h>
#include <string.h>
#include <cstdint>
#include <new>
#include "absl/status/status.h"
@ -57,13 +57,13 @@ class ChannelData {
message_size_service_config_parser_index_(
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 {
return message_size_service_config_parser_index_;
}
private:
int max_recv_size_;
absl::optional<uint32_t> max_recv_size_;
const size_t message_size_service_config_parser_index_;
};
@ -86,10 +86,10 @@ class CallData {
const MessageSizeParsedConfig* limits =
MessageSizeParsedConfig::GetFromCallContext(
args.context, chand->message_size_service_config_parser_index());
if (limits != nullptr && limits->limits().max_recv_size >= 0 &&
(limits->limits().max_recv_size < max_recv_message_length_ ||
max_recv_message_length_ < 0)) {
max_recv_message_length_ = limits->limits().max_recv_size;
if (limits != nullptr && limits->max_recv_size().has_value() &&
(!max_recv_message_length_.has_value() ||
*limits->max_recv_size() < *max_recv_message_length_)) {
max_recv_message_length_ = *limits->max_recv_size();
}
}
@ -117,7 +117,7 @@ class CallData {
grpc_metadata_batch* recv_initial_metadata_ = nullptr;
// Fields for handling recv_message_ready callback
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;
absl::optional<SliceBuffer>* recv_message_ = 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)) {
return calld->ContinueRecvMessageReadyCallback(absl::OkStatus());
}
if (calld->max_recv_message_length_ >= 0 &&
if (calld->max_recv_message_length_.has_value() &&
(*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());
calld->error_ = grpc_error_set_int(
GRPC_ERROR_CREATE(
absl::StrFormat("Received message larger than max (%u vs. %d)",
(*calld->recv_message_)->Length(),
calld->max_recv_message_length_)),
*calld->max_recv_message_length_)),
StatusIntProperty::kRpcStatus, GRPC_STATUS_RESOURCE_EXHAUSTED);
return calld->ContinueRecvMessageReadyCallback(calld->error_);
}

@ -18,17 +18,11 @@
#include "src/core/ext/filters/message_size/message_size_filter.h"
#include <algorithm>
#include <map>
#include <cstdint>
#include <new>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/types/optional.h"
#include <grpc/impl/codegen/grpc_types.h>
#include <grpc/status.h>
@ -38,7 +32,6 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/channel/channel_stack_builder.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/status_helper.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));
}
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
//
absl::StatusOr<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
std::unique_ptr<ServiceConfigParser::ParsedConfig>
MessageSizeParser::ParsePerMethodParams(const ChannelArgs& /*args*/,
const Json& json) {
std::vector<grpc_error_handle> error_list;
// Max request size.
int max_request_message_bytes = -1;
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);
const Json& json,
ValidationErrors* errors) {
return LoadFromJson<std::unique_ptr<MessageSizeParsedConfig>>(
json, JsonArgs(), errors);
}
void MessageSizeParser::Register(CoreConfiguration::Builder* builder) {
@ -135,23 +124,11 @@ size_t MessageSizeParser::ParserIndex() {
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 {
struct channel_data {
grpc_core::MessageSizeParsedConfig::message_size_limits limits;
grpc_core::MessageSizeParsedConfig limits;
const size_t service_config_parser_index{
grpc_core::MessageSizeParser::ParserIndex()};
};
@ -169,27 +146,30 @@ struct call_data {
// 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
// size to the receive limit.
const grpc_core::MessageSizeParsedConfig* limits =
const grpc_core::MessageSizeParsedConfig* config_from_call_context =
grpc_core::MessageSizeParsedConfig::GetFromCallContext(
args.context, chand.service_config_parser_index);
if (limits != nullptr) {
if (limits->limits().max_send_size >= 0 &&
(limits->limits().max_send_size < this->limits.max_send_size ||
this->limits.max_send_size < 0)) {
this->limits.max_send_size = limits->limits().max_send_size;
if (config_from_call_context != nullptr) {
absl::optional<uint32_t> max_send_size = limits.max_send_size();
absl::optional<uint32_t> max_recv_size = limits.max_recv_size();
if (config_from_call_context->max_send_size().has_value() &&
(!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 &&
(limits->limits().max_recv_size < this->limits.max_recv_size ||
this->limits.max_recv_size < 0)) {
this->limits.max_recv_size = limits->limits().max_recv_size;
if (config_from_call_context->max_recv_size().has_value() &&
(!max_recv_size.has_value() ||
*config_from_call_context->max_recv_size() < *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() {}
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
// recv_message_ready up-call on transport_stream_op, and remember to
// 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) {
grpc_call_element* elem = static_cast<grpc_call_element*>(user_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() >
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_CREATE(absl::StrFormat(
"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_STATUS_RESOURCE_EXHAUSTED);
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) {
call_data* calld = static_cast<call_data*>(elem->call_data);
// 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() >
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(
op,
grpc_error_set_int(GRPC_ERROR_CREATE(absl::StrFormat(
"Sent message larger than max (%u vs. %d)",
op->payload->send_message.send_message->Length(),
calld->limits.max_send_size)),
*calld->limits.max_send_size())),
grpc_core::StatusIntProperty::kRpcStatus,
GRPC_STATUS_RESOURCE_EXHAUSTED),
calld->call_combiner);
@ -317,21 +298,13 @@ static void message_size_destroy_call_elem(
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.
static grpc_error_handle message_size_init_channel_elem(
grpc_channel_element* elem, grpc_channel_element_args* args) {
GPR_ASSERT(!args->is_last);
channel_data* chand = static_cast<channel_data*>(elem->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));
return absl::OkStatus();
}
@ -375,10 +348,11 @@ static bool maybe_add_message_size_filter(
if (channel_args.WantMinimalStack()) {
return true;
}
grpc_core::MessageSizeParsedConfig::message_size_limits lim =
get_message_size_limits(channel_args);
grpc_core::MessageSizeParsedConfig limits =
grpc_core::MessageSizeParsedConfig::GetFromChannelArgs(channel_args);
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();
if (enable) builder->PrependFilter(&grpc_message_size_filter);
return true;

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

File diff suppressed because it is too large Load Diff

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

@ -38,7 +38,7 @@
#include <grpc/status.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_http_filters.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)}};
}
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::Object json;
json.emplace("addressPrefix",
@ -176,7 +172,7 @@ Json ParseCidrRangeToJson(const envoy_config_core_v3_CidrRange* range) {
envoy_config_core_v3_CidrRange_address_prefix(range)));
const auto* prefix_len = envoy_config_core_v3_CidrRange_prefix_len(range);
if (prefix_len != nullptr) {
json.emplace("prefixLen", ParseUInt32ValueToJson(prefix_len));
json.emplace("prefixLen", google_protobuf_UInt32Value_value(prefix_len));
}
return json;
}

@ -20,6 +20,7 @@
#include <cstdint>
#include <cstring>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
@ -392,6 +393,26 @@ class AutoLoader<absl::optional<T>> final : public LoadOptional {
~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.
// Simply keeps a static AutoLoader<T> and returns a pointer to that.
template <typename T>

@ -58,7 +58,7 @@
namespace grpc_core {
// 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> {
public:
static absl::string_view ChannelArgName() {

@ -20,113 +20,134 @@
#include <string.h>
#include <map>
#include <string>
#include <utility>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include <grpc/support/log.h>
#include "absl/types/optional.h"
#include "src/core/lib/config/core_configuration.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_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/slice/slice.h"
#include "src/core/lib/slice/slice_internal.h"
namespace grpc_core {
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();
absl::Status status;
auto service_config = MakeRefCounted<ServiceConfigImpl>(
args, std::string(json_string), std::move(*json), &status);
if (!status.ok()) return status;
return service_config;
namespace {
struct MethodConfig {
struct Name {
absl::optional<std::string> service;
absl::optional<std::string> method;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader = JsonObjectLoader<Name>()
.OptionalField("service", &Name::service)
.OptionalField("method", &Name::method)
.Finish();
return loader;
}
ServiceConfigImpl::ServiceConfigImpl(const ChannelArgs& args,
std::string json_string, Json json,
absl::Status* status)
: 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;
void JsonPostLoad(const Json&, const JsonArgs&, ValidationErrors* errors) {
if (!service.has_value() && method.has_value()) {
errors->AddError("method name populated without service name");
}
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());
if (!errors.empty()) {
*status = absl::InvalidArgumentError(absl::StrCat(
"Service config parsing errors: [", absl::StrJoin(errors, "; "), "]"));
std::string Path() const {
if (!service.has_value() || service->empty()) return "";
return absl::StrCat("/", *service, "/",
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() {
for (auto& p : parsed_method_configs_map_) {
CSliceUnref(p.first);
} // namespace
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,
const Json& json,
size_t index) {
std::vector<std::string> errors;
const ServiceConfigParser::ParsedConfigVector* vector_ptr = nullptr;
// Parse method config with each registered parser.
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");
RefCountedPtr<ServiceConfig> ServiceConfigImpl::Create(
const ChannelArgs& args, const Json& json, absl::string_view json_string,
ValidationErrors* errors) {
if (json.type() != Json::Type::OBJECT) {
errors->AddError("is not an object");
return nullptr;
}
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 {
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
// 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) {
errors.emplace_back(
"field:name error:multiple method configs with same name");
errors->AddError(absl::StrCat("multiple method configs for path ",
StringViewFromSlice(key)));
// The map entry already existed, so we need to unref the
// key we just created.
CSliceUnref(key);
@ -137,80 +158,13 @@ absl::Status ServiceConfigImpl::ParseJsonMethodConfig(const ChannelArgs& args,
}
}
}
}
if (!errors.empty()) {
return absl::InvalidArgumentError(
absl::StrCat("index ", index, ": [", absl::StrJoin(errors, "; "), "]"));
}
return absl::OkStatus();
return service_config;
}
absl::Status ServiceConfigImpl::ParsePerMethodParams(const ChannelArgs& args) {
auto it = json_.object_value().find("methodConfig");
if (it == json_.object_value().end()) return absl::OkStatus();
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();
ServiceConfigImpl::~ServiceConfigImpl() {
for (auto& p : parsed_method_configs_map_) {
CSliceUnref(p.first);
}
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*

@ -26,7 +26,6 @@
#include <unordered_map>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
@ -35,6 +34,7 @@
#include "src/core/lib/channel/channel_args.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/service_config/service_config.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(
const ChannelArgs& args, absl::string_view json_string);
ServiceConfigImpl(const ChannelArgs& args, std::string json_string, Json json,
absl::Status* status);
// Alternate forms that are useful in edge cases.
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;
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;
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_;
Json json_;
std::vector<std::unique_ptr<ServiceConfigParser::ParsedConfig>>
parsed_global_configs_;
ServiceConfigParser::ParsedConfigVector parsed_global_configs_;
// 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
// vector for multiple names.
@ -118,11 +115,11 @@ class ServiceConfigImpl final : public ServiceConfig {
const ServiceConfigParser::ParsedConfigVector* default_method_config_vector_ =
nullptr;
// Storage for all the vectors that are being used in
// parsed_method_configs_table_.
std::vector<std::unique_ptr<ServiceConfigParser::ParsedConfigVector>>
// parsed_method_configs_map_ and default_method_config_vector_.
std::vector<ServiceConfigParser::ParsedConfigVector>
parsed_method_config_vectors_storage_;
};
} // 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 "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include <grpc/support/log.h>
@ -49,43 +47,28 @@ void ServiceConfigParser::Builder::RegisterParser(
registered_parsers_.emplace_back(std::move(parser));
}
absl::StatusOr<ServiceConfigParser::ParsedConfigVector>
ServiceConfigParser::ParsedConfigVector
ServiceConfigParser::ParseGlobalParameters(const ChannelArgs& args,
const Json& json) const {
const Json& json,
ValidationErrors* errors) const {
ParsedConfigVector parsed_global_configs;
std::vector<std::string> errors;
for (size_t i = 0; i < registered_parsers_.size(); i++) {
auto parsed_config = registered_parsers_[i]->ParseGlobalParams(args, json);
if (!parsed_config.ok()) {
errors.emplace_back(parsed_config.status().message());
} else {
parsed_global_configs.push_back(std::move(*parsed_config));
for (auto& parser : registered_parsers_) {
parsed_global_configs.push_back(
parser->ParseGlobalParams(args, json, errors));
}
}
if (!errors.empty()) {
return absl::InvalidArgumentError(absl::StrJoin(errors, "; "));
}
return std::move(parsed_global_configs);
return parsed_global_configs;
}
absl::StatusOr<ServiceConfigParser::ParsedConfigVector>
ServiceConfigParser::ParsedConfigVector
ServiceConfigParser::ParsePerMethodParameters(const ChannelArgs& args,
const Json& json) const {
const Json& json,
ValidationErrors* errors) const {
ParsedConfigVector parsed_method_configs;
std::vector<std::string> errors;
for (size_t i = 0; i < registered_parsers_.size(); ++i) {
auto parsed_config =
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, "; "));
for (auto& parser : registered_parsers_) {
parsed_method_configs.push_back(
parser->ParsePerMethodParams(args, json, errors));
}
return std::move(parsed_method_configs);
return parsed_method_configs;
}
size_t ServiceConfigParser::GetParserIndex(absl::string_view name) const {

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

@ -60,8 +60,22 @@ grpc_cc_test(
)
grpc_cc_test(
name = "service_config_test",
srcs = ["service_config_test.cc"],
name = "client_channel_service_config_test",
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 = [
"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.
//
#include <string>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@ -111,15 +108,14 @@ TEST_F(RlsConfigParsingTest, TopLevelFieldsWrongTypes) {
auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
service_config.status().message(),
::testing::HasSubstr(
"errors validing RLS LB policy config: ["
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingConfig "
"error:errors validing RLS LB policy config: ["
"field:childPolicy error:is not an array; "
"field:childPolicyConfigTargetFieldName error:is not a string; "
"field:routeLookupChannelServiceConfig error:"
"INVALID_ARGUMENT:JSON value is not an object; "
"field:routeLookupConfig error:is not an object]"))
"field:routeLookupChannelServiceConfig error:is not an object; "
"field:routeLookupConfig error:is not an object]]")
<< service_config.status();
}
@ -191,17 +187,13 @@ TEST_F(RlsConfigParsingTest, InvalidRlsChannelServiceConfig) {
auto service_config =
ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex(
"errors validing RLS LB policy config: \\["
"field:routeLookupChannelServiceConfig error:"
"INVALID_ARGUMENT:Service config parsing errors: \\["
"error parsing client channel global parameters: "
"UNKNOWN:Client channel global parser"
".*children:.*"
"\\[UNKNOWN:field:loadBalancingPolicy error:Unknown lb policy.*"
"field:routeLookupConfig error:field not present\\]"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:loadBalancingConfig "
"error:errors validing RLS LB policy config: ["
"field:routeLookupChannelServiceConfig.loadBalancingPolicy "
"error:unknown LB policy \"unknown\"; "
"field:routeLookupConfig error:field not present]]")
<< 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 <string>
#include "absl/status/status.h"
#include "gmock/gmock.h"
#include "absl/status/statusor.h"
#include "gtest/gtest.h"
#include <grpc/grpc.h>
@ -28,9 +26,6 @@
#include "src/core/lib/service_config/service_config_impl.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 testing {
namespace {
@ -148,10 +143,9 @@ TEST(RbacServiceConfigParsingTest, BadRbacPolicyType) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG
"field:rbacPolicy error:type should be ARRAY"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy error:is not an array]")
<< service_config.status();
}
@ -168,11 +162,9 @@ TEST(RbacServiceConfigParsingTest, BadRulesType) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"field:rules error:type should be OBJECT"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules error:is not an object]")
<< service_config.status();
}
@ -194,12 +186,12 @@ TEST(RbacServiceConfigParsingTest, BadActionAndPolicyType) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"field:action error:type should be NUMBER.*"
"field:policies error:type should be OBJECT"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules.action "
"error:is not a number; "
"field:methodConfig[0].rbacPolicy[0].rules.policies "
"error:is not an object]")
<< service_config.status();
}
@ -224,13 +216,12 @@ TEST(RbacServiceConfigParsingTest, MissingPermissionAndPrincipals) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"policies key:'policy'" CHILD_ERROR_TAG
"field:permissions error:does not exist.*"
"field:principals error:does not exist"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions error:field not present; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals error:field not present]")
<< service_config.status();
}
@ -257,13 +248,12 @@ TEST(RbacServiceConfigParsingTest, EmptyPrincipalAndPermission) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex(
"Rbac parser" CHILD_ERROR_TAG "rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"policies key:'policy'" CHILD_ERROR_TAG
"permissions\\[0\\]" CHILD_ERROR_TAG "No valid rule found.*"
"principals\\[0\\]" CHILD_ERROR_TAG "No valid id found"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[0] error:no valid rule found; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[0] error:no valid id found]")
<< service_config.status();
}
@ -370,53 +360,51 @@ TEST(RbacServiceConfigParsingTest, VariousPermissionsAndPrincipalsBadTypes) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex(
"Rbac parser" CHILD_ERROR_TAG "rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"policies key:'policy'" CHILD_ERROR_TAG
"permissions\\[0\\]" CHILD_ERROR_TAG
"field:andRules error:type should be OBJECT.*"
"permissions\\[1\\]" CHILD_ERROR_TAG
"field:orRules error:type should be OBJECT.*"
"permissions\\[2\\]" CHILD_ERROR_TAG
"field:any error:type should be BOOLEAN.*"
"permissions\\[3\\]" CHILD_ERROR_TAG
"field:header error:type should be OBJECT.*"
"permissions\\[4\\]" CHILD_ERROR_TAG
"field:urlPath error:type should be OBJECT.*"
"permissions\\[5\\]" CHILD_ERROR_TAG
"field:destinationIp error:type should be OBJECT.*"
"permissions\\[6\\]" CHILD_ERROR_TAG
"field:destinationPort error:failed to parse.*"
"permissions\\[7\\]" CHILD_ERROR_TAG
"field:metadata error:type should be OBJECT.*"
"permissions\\[8\\]" CHILD_ERROR_TAG
"field:notRule error:type should be OBJECT.*"
"permissions\\[9\\]" CHILD_ERROR_TAG
"field:requestedServerName error:type should be OBJECT.*"
"principals\\[0\\]" CHILD_ERROR_TAG
"field:andIds error:type should be OBJECT.*"
"principals\\[1\\]" CHILD_ERROR_TAG
"field:orIds error:type should be OBJECT.*"
"principals\\[2\\]" CHILD_ERROR_TAG
"field:any error:type should be BOOLEAN.*"
"principals\\[3\\]" CHILD_ERROR_TAG
"field:authenticated error:type should be OBJECT.*"
"principals\\[4\\]" CHILD_ERROR_TAG
"field:sourceIp error:type should be OBJECT.*"
"principals\\[5\\]" CHILD_ERROR_TAG
"field:directRemoteIp error:type should be OBJECT.*"
"principals\\[6\\]" CHILD_ERROR_TAG
"field:remoteIp error:type should be OBJECT.*"
"principals\\[7\\]" CHILD_ERROR_TAG
"field:header error:type should be OBJECT.*"
"principals\\[8\\]" CHILD_ERROR_TAG
"field:urlPath error:type should be OBJECT.*"
"principals\\[9\\]" CHILD_ERROR_TAG
"field:metadata error:type should be OBJECT.*"
"principals\\[10\\]" CHILD_ERROR_TAG
"field:notId error:type should be OBJECT.*"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[0].andRules error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[1].orRules error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[2].any error:is not a boolean; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[3].header error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[4].urlPath error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[5].destinationIp error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[6].destinationPort "
"error:failed to parse non-negative number; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[7].metadata error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[8].notRule error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[9].requestedServerName error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[0].andIds error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[10].notId error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[1].orIds error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[2].any error:is not a boolean; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[3].authenticated error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[4].sourceIp error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[5].directRemoteIp error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[6].remoteIp error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[7].header error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[8].urlPath error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".principals[9].metadata error:is not an object]")
<< service_config.status();
}
@ -484,7 +472,8 @@ TEST(RbacServiceConfigParsingTest, HeaderMatcherBadTypes) {
" {\"header\":{\"name\":\"name\", \"presentMatch\":1}},\n"
" {\"header\":{\"name\":\"name\", \"prefixMatch\":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"
" \"principals\":[]\n"
" }\n"
@ -496,26 +485,26 @@ TEST(RbacServiceConfigParsingTest, HeaderMatcherBadTypes) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex(
"Rbac parser" CHILD_ERROR_TAG "rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"policies key:'policy'" CHILD_ERROR_TAG
"permissions\\[0\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:invertMatch error:type should be BOOLEAN.*"
"field:exactMatch error:type should be STRING.*"
"permissions\\[1\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:safeRegexMatch error:type should be OBJECT.*"
"permissions\\[2\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:rangeMatch error:type should be OBJECT.*"
"permissions\\[3\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:presentMatch error:type should be BOOLEAN.*"
"permissions\\[4\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:prefixMatch error:type should be STRING.*"
"permissions\\[5\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:suffixMatch error:type should be STRING.*"
"permissions\\[6\\]" CHILD_ERROR_TAG "header" CHILD_ERROR_TAG
"field:containsMatch error:type should be STRING.*"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[0].header.exactMatch error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[0].header.invertMatch error:is not a boolean; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[1].header.safeRegexMatch error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[2].header.rangeMatch error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[3].header.presentMatch error:is not a boolean; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[4].header.prefixMatch error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[5].header.suffixMatch error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[6].header.containsMatch error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[7].header error:no valid matcher found]")
<< service_config.status();
}
@ -578,7 +567,8 @@ TEST(RbacServiceConfigParsingTest, StringMatcherBadTypes) {
" {\"requestedServerName\":{\"prefix\":1}},\n"
" {\"requestedServerName\":{\"suffix\":1}},\n"
" {\"requestedServerName\":{\"safeRegex\":1}},\n"
" {\"requestedServerName\":{\"contains\":1}}\n"
" {\"requestedServerName\":{\"contains\":1}},\n"
" {\"requestedServerName\":{}}\n"
" ],\n"
" \"principals\":[]\n"
" }\n"
@ -590,27 +580,27 @@ TEST(RbacServiceConfigParsingTest, StringMatcherBadTypes) {
ChannelArgs args = ChannelArgs().Set(GRPC_ARG_PARSE_RBAC_METHOD_CONFIG, 1);
auto service_config = ServiceConfigImpl::Create(args, test_json);
EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
EXPECT_THAT(
std::string(service_config.status().message()),
::testing::ContainsRegex("Rbac parser" CHILD_ERROR_TAG
"rbacPolicy\\[0\\]" CHILD_ERROR_TAG
"policies key:'policy'" CHILD_ERROR_TAG
"permissions\\[0\\]" CHILD_ERROR_TAG
"requestedServerName" CHILD_ERROR_TAG
"field:ignoreCase error:type should be BOOLEAN.*"
"field:exact error:type should be STRING.*"
"permissions\\[1\\]" CHILD_ERROR_TAG
"requestedServerName" CHILD_ERROR_TAG
"field:prefix error:type should be STRING.*"
"permissions\\[2\\]" CHILD_ERROR_TAG
"requestedServerName" CHILD_ERROR_TAG
"field:suffix error:type should be STRING.*"
"permissions\\[3\\]" CHILD_ERROR_TAG
"requestedServerName" CHILD_ERROR_TAG
"field:safeRegex error:type should be OBJECT.*"
"permissions\\[4\\]" CHILD_ERROR_TAG
"requestedServerName" CHILD_ERROR_TAG
"field:contains error:type should be STRING.*"))
EXPECT_EQ(service_config.status().message(),
"errors validating service config: ["
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[0].requestedServerName.exact error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[0].requestedServerName.ignoreCase "
"error:is not a boolean; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[1].requestedServerName.prefix "
"error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[2].requestedServerName.suffix "
"error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[3].requestedServerName.safeRegex "
"error:is not an object; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[4].requestedServerName.contains "
"error:is not a string; "
"field:methodConfig[0].rbacPolicy[0].rules.policies[\"policy\"]"
".permissions[5].requestedServerName error:no valid matcher found]")
<< service_config.status();
}

@ -49,6 +49,7 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
TypeParam value = 0;
TypeParam optional_value = 0;
absl::optional<TypeParam> absl_optional_value;
std::unique_ptr<TypeParam> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
@ -57,6 +58,7 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -79,6 +81,13 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 0);
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.
test_struct = Parse<TestStruct>("{}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
@ -88,20 +97,23 @@ TYPED_TEST_P(SignedIntegerTest, IntegerFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 7);
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -125,6 +137,7 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
TypeParam value = 0;
TypeParam optional_value = 0;
absl::optional<TypeParam> absl_optional_value;
std::unique_ptr<TypeParam> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
@ -133,6 +146,7 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -156,6 +170,13 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 0);
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.
test_struct = Parse<TestStruct>("{}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
@ -165,21 +186,24 @@ TYPED_TEST_P(UnsignedIntegerTest, IntegerFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(test_struct->value, 5);
EXPECT_EQ(test_struct->optional_value, 7);
ASSERT_TRUE(test_struct->absl_optional_value.has_value());
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -203,6 +227,7 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
TypeParam value = 0;
TypeParam optional_value = 0;
absl::optional<TypeParam> absl_optional_value;
std::unique_ptr<TypeParam> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
@ -211,6 +236,7 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -233,6 +259,13 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
EXPECT_NEAR(test_struct->value, 5.2, 0.0001);
EXPECT_EQ(test_struct->optional_value, 0);
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.
test_struct = Parse<TestStruct>("{}");
EXPECT_EQ(test_struct.status().code(), absl::StatusCode::kInvalidArgument);
@ -242,21 +275,24 @@ TYPED_TEST_P(FloatingPointTest, FloatFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_NEAR(test_struct->value, 5.2, 0.0001);
EXPECT_NEAR(test_struct->optional_value, 7.5, 0.0001);
ASSERT_TRUE(test_struct->absl_optional_value.has_value());
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -275,6 +311,7 @@ TEST(JsonObjectLoader, BooleanFields) {
bool value = false;
bool optional_value = true;
absl::optional<bool> absl_optional_value;
std::unique_ptr<bool> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
@ -283,6 +320,7 @@ TEST(JsonObjectLoader, BooleanFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -308,20 +346,23 @@ TEST(JsonObjectLoader, BooleanFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(test_struct->value, true);
EXPECT_EQ(test_struct->optional_value, false);
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -335,6 +376,7 @@ TEST(JsonObjectLoader, StringFields) {
std::string value;
std::string 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 auto* loader =
@ -343,6 +385,7 @@ TEST(JsonObjectLoader, StringFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -362,20 +405,23 @@ TEST(JsonObjectLoader, StringFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(test_struct->value, "foo");
EXPECT_EQ(test_struct->optional_value, "bar");
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -389,6 +435,7 @@ TEST(JsonObjectLoader, DurationFields) {
Duration value = Duration::Zero();
Duration optional_value = Duration::Zero();
absl::optional<Duration> absl_optional_value;
std::unique_ptr<Duration> unique_ptr_value;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
@ -397,6 +444,7 @@ TEST(JsonObjectLoader, DurationFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -441,20 +489,23 @@ TEST(JsonObjectLoader, DurationFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(test_struct->value, Duration::Seconds(3));
EXPECT_EQ(test_struct->optional_value, Duration::Milliseconds(3200));
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -468,6 +519,7 @@ TEST(JsonObjectLoader, JsonObjectFields) {
Json::Object value;
Json::Object 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 auto* loader =
@ -476,6 +528,7 @@ TEST(JsonObjectLoader, JsonObjectFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -495,21 +548,24 @@ TEST(JsonObjectLoader, JsonObjectFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(Json{test_struct->value}.Dump(), "{\"a\":1}");
EXPECT_EQ(Json{test_struct->optional_value}.Dump(), "{\"b\":2}");
ASSERT_TRUE(test_struct->absl_optional_value.has_value());
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
}
@ -523,6 +579,7 @@ TEST(JsonObjectLoader, MapFields) {
std::map<std::string, int32_t> value;
std::map<std::string, std::string> 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 auto* loader =
@ -531,6 +588,7 @@ TEST(JsonObjectLoader, MapFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -551,7 +609,8 @@ TEST(JsonObjectLoader, MapFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_THAT(test_struct->value,
::testing::ElementsAre(::testing::Pair("a", 1)));
@ -560,15 +619,19 @@ TEST(JsonObjectLoader, MapFields) {
ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_THAT(*test_struct->absl_optional_value,
::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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
// Wrong JSON type for map value.
@ -593,6 +656,7 @@ TEST(JsonObjectLoader, VectorFields) {
std::vector<int32_t> value;
std::vector<std::string> 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 auto* loader =
@ -601,6 +665,7 @@ TEST(JsonObjectLoader, VectorFields) {
.OptionalField("optional_value", &TestStruct::optional_value)
.OptionalField("absl_optional_value",
&TestStruct::absl_optional_value)
.OptionalField("unique_ptr_value", &TestStruct::unique_ptr_value)
.Finish();
return loader;
}
@ -620,7 +685,8 @@ TEST(JsonObjectLoader, VectorFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_THAT(test_struct->value, ::testing::ElementsAre(4, 5, 6));
EXPECT_THAT(test_struct->optional_value,
@ -628,15 +694,18 @@ TEST(JsonObjectLoader, VectorFields) {
ASSERT_TRUE(test_struct->absl_optional_value.has_value());
EXPECT_THAT(*test_struct->absl_optional_value,
::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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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]")
<< test_struct.status();
// Wrong JSON type for map value.
@ -674,6 +743,7 @@ TEST(JsonObjectLoader, NestedStructFields) {
NestedStruct outer;
NestedStruct optional_outer;
absl::optional<NestedStruct> absl_optional_outer;
std::unique_ptr<NestedStruct> unique_ptr_outer;
static const JsonLoaderInterface* JsonLoader(const JsonArgs&) {
static const auto* loader =
@ -682,6 +752,7 @@ TEST(JsonObjectLoader, NestedStructFields) {
.OptionalField("optional_outer", &TestStruct::optional_outer)
.OptionalField("absl_optional_outer",
&TestStruct::absl_optional_outer)
.OptionalField("unique_ptr_outer", &TestStruct::unique_ptr_outer)
.Finish();
return loader;
}
@ -708,22 +779,26 @@ TEST(JsonObjectLoader, NestedStructFields) {
// Optional fields present.
test_struct = Parse<TestStruct>(
"{\"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();
EXPECT_EQ(test_struct->outer.inner, 1);
EXPECT_EQ(test_struct->optional_outer.inner, 2);
ASSERT_TRUE(test_struct->absl_optional_outer.has_value());
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.
test_struct = Parse<TestStruct>(
"{\"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().message(),
"errors validating JSON: ["
"field:absl_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();
// Wrong JSON type for inner value.
test_struct = Parse<TestStruct>(
@ -774,6 +849,13 @@ TEST(JsonObjectLoader, BareBool) {
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) {
auto parsed = Parse<std::vector<int32_t>>("[1, 2, 3]");
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 "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_service_config_parser.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\"}}}},"
// destination IP match with prefix len
"{\"destinationIp\":{"
"\"addressPrefix\":\"127.0.0\",\"prefixLen\":{\"value\":24}}},"
"\"addressPrefix\":\"127.0.0\",\"prefixLen\":24}},"
// destination IP match
"{\"destinationIp\":{\"addressPrefix\":\"10.0.0\"}},"
// destination port match

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

@ -435,7 +435,7 @@ resolver_component_tests:
- {address: '1.2.3.4:443', is_balancer: false}
do_ordered_address_comparison: false
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
enable_srv_queries: true
enable_txt_queries: true
@ -465,7 +465,7 @@ resolver_component_tests:
- {address: '1.2.3.4:443', is_balancer: false}
do_ordered_address_comparison: false
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
enable_srv_queries: true
enable_txt_queries: true

@ -1075,6 +1075,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.h \
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.h \
src/core/ext/filters/client_channel/connector.h \
@ -1143,8 +1145,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/xds/xds_resolver.cc \
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.h \
src/core/ext/filters/client_channel/retry_service_config.cc \
@ -1163,8 +1163,8 @@ src/core/ext/filters/deadline/deadline_filter.cc \
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.h \
src/core/ext/filters/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.cc \
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.h \
src/core/ext/filters/http/client_authority_filter.cc \
@ -2250,6 +2250,7 @@ src/core/lib/iomgr/wakeup_fd_posix.cc \
src/core/lib/iomgr/wakeup_fd_posix.h \
src/core/lib/json/json.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.h \
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.h \
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.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/xds/xds_resolver.cc \
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.h \
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/fault_injection/fault_injection_filter.cc \
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/service_config_parser.h \
src/core/ext/filters/fault_injection/fault_injection_service_config_parser.cc \
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.h \
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/json/json.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.h \
src/core/lib/json/json_reader.cc \

@ -1919,6 +1919,30 @@
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
"ci_platforms": [
"linux",
"mac",
"posix",
"windows"
],
"cpu_cost": 1.0,
"exclude_configs": [],
"exclude_iomgrs": [],
"flaky": false,
"gtest": true,
"language": "c++",
"name": "client_channel_service_config_test",
"platforms": [
"linux",
"mac",
"posix",
"windows"
],
"uses_polling": true
},
{
"args": [],
"benchmark": false,
@ -4621,6 +4645,30 @@
],
"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": [],
"benchmark": false,
@ -5713,6 +5761,30 @@
],
"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": [],
"benchmark": false,

Loading…
Cancel
Save