diff --git a/BUILD b/BUILD
index fcd3f6cc596..9c0acfdc1ff 100644
--- a/BUILD
+++ b/BUILD
@@ -1769,6 +1769,9 @@ grpc_cc_library(
hdrs = [
"src/core/lib/avl/avl.h",
],
+ external_deps = [
+ "absl/container:inlined_vector",
+ ],
deps = [
"gpr_platform",
],
@@ -2413,12 +2416,18 @@ grpc_cc_library(
external_deps = [
"absl/strings",
"absl/strings:str_format",
+ "absl/types:variant",
+ "absl/types:optional",
],
language = "c++",
deps = [
+ "avl",
"channel_stack_type",
"gpr_base",
"grpc_codegen",
+ "match",
+ "ref_counted",
+ "ref_counted_ptr",
"useful",
],
)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ec5384416af..e536e19cb27 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -631,7 +631,6 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_c bin_decoder_test)
add_dependencies(buildtests_c bin_encoder_test)
add_dependencies(buildtests_c buffer_list_test)
- add_dependencies(buildtests_c channel_args_test)
add_dependencies(buildtests_c channel_stack_test)
add_dependencies(buildtests_c check_gcp_environment_linux_test)
add_dependencies(buildtests_c check_gcp_environment_windows_test)
@@ -806,6 +805,7 @@ if(gRPC_BUILD_TESTS)
add_dependencies(buildtests_cxx certificate_provider_registry_test)
add_dependencies(buildtests_cxx certificate_provider_store_test)
add_dependencies(buildtests_cxx cfstream_test)
+ add_dependencies(buildtests_cxx channel_args_test)
add_dependencies(buildtests_cxx channel_arguments_test)
add_dependencies(buildtests_cxx channel_creds_registry_test)
add_dependencies(buildtests_cxx channel_filter_test)
@@ -4680,33 +4680,6 @@ target_link_libraries(buffer_list_test
)
-endif()
-if(gRPC_BUILD_TESTS)
-
-add_executable(channel_args_test
- test/core/channel/channel_args_test.cc
-)
-
-target_include_directories(channel_args_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}
-)
-
-target_link_libraries(channel_args_test
- ${_gRPC_ALLTARGETS_LIBRARIES}
- grpc_test_util
-)
-
-
endif()
if(gRPC_BUILD_TESTS)
@@ -7726,6 +7699,7 @@ target_include_directories(avl_test
target_link_libraries(avl_test
${_gRPC_PROTOBUF_LIBRARIES}
${_gRPC_ALLTARGETS_LIBRARIES}
+ absl::inlined_vector
)
@@ -8489,6 +8463,41 @@ target_link_libraries(cfstream_test
)
+endif()
+if(gRPC_BUILD_TESTS)
+
+add_executable(channel_args_test
+ test/core/channel/channel_args_test.cc
+ third_party/googletest/googletest/src/gtest-all.cc
+ third_party/googletest/googlemock/src/gmock-all.cc
+)
+
+target_include_directories(channel_args_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(channel_args_test
+ ${_gRPC_PROTOBUF_LIBRARIES}
+ ${_gRPC_ALLTARGETS_LIBRARIES}
+ grpc_test_util
+)
+
+
endif()
if(gRPC_BUILD_TESTS)
diff --git a/build_autogenerated.yaml b/build_autogenerated.yaml
index 8ebf1d4ccbe..d58dd9e1058 100644
--- a/build_autogenerated.yaml
+++ b/build_autogenerated.yaml
@@ -728,7 +728,9 @@ libs:
- src/core/lib/gprpp/chunked_vector.h
- src/core/lib/gprpp/cpp_impl_of.h
- src/core/lib/gprpp/dual_ref_counted.h
+ - src/core/lib/gprpp/match.h
- src/core/lib/gprpp/orphanable.h
+ - src/core/lib/gprpp/overload.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/table.h
@@ -1907,7 +1909,9 @@ libs:
- src/core/lib/gprpp/chunked_vector.h
- src/core/lib/gprpp/cpp_impl_of.h
- src/core/lib/gprpp/dual_ref_counted.h
+ - src/core/lib/gprpp/match.h
- src/core/lib/gprpp/orphanable.h
+ - src/core/lib/gprpp/overload.h
- src/core/lib/gprpp/ref_counted.h
- src/core/lib/gprpp/ref_counted_ptr.h
- src/core/lib/gprpp/table.h
@@ -3330,15 +3334,6 @@ targets:
- test/core/iomgr/buffer_list_test.cc
deps:
- grpc_test_util
-- name: channel_args_test
- build: test
- language: c
- headers: []
- src:
- - test/core/channel/channel_args_test.cc
- deps:
- - grpc_test_util
- uses_polling: false
- name: channel_stack_test
build: test
language: c
@@ -4546,7 +4541,8 @@ targets:
- src/core/lib/avl/avl.h
src:
- test/core/avl/avl_test.cc
- deps: []
+ deps:
+ - absl/container:inlined_vector
uses_polling: false
- name: aws_request_signer_test
gtest: true
@@ -4862,6 +4858,16 @@ targets:
- test/cpp/end2end/test_service_impl.cc
deps:
- grpc++_test_util
+- name: channel_args_test
+ gtest: true
+ build: test
+ language: c++
+ headers: []
+ src:
+ - test/core/channel/channel_args_test.cc
+ deps:
+ - grpc_test_util
+ uses_polling: false
- name: channel_arguments_test
gtest: true
build: test
diff --git a/gRPC-C++.podspec b/gRPC-C++.podspec
index fc123d5ed7d..f97985d71c5 100644
--- a/gRPC-C++.podspec
+++ b/gRPC-C++.podspec
@@ -688,9 +688,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/host_port.h',
'src/core/lib/gprpp/manual_constructor.h',
+ 'src/core/lib/gprpp/match.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/mpscq.h',
'src/core/lib/gprpp/orphanable.h',
+ 'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/stat.h',
@@ -1493,9 +1495,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/host_port.h',
'src/core/lib/gprpp/manual_constructor.h',
+ 'src/core/lib/gprpp/match.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/mpscq.h',
'src/core/lib/gprpp/orphanable.h',
+ 'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/stat.h',
diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec
index 42a3e29e62a..0e6a8421390 100644
--- a/gRPC-Core.podspec
+++ b/gRPC-Core.podspec
@@ -1087,10 +1087,12 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/host_port.cc',
'src/core/lib/gprpp/host_port.h',
'src/core/lib/gprpp/manual_constructor.h',
+ 'src/core/lib/gprpp/match.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/mpscq.cc',
'src/core/lib/gprpp/mpscq.h',
'src/core/lib/gprpp/orphanable.h',
+ 'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/stat.h',
@@ -2093,9 +2095,11 @@ Pod::Spec.new do |s|
'src/core/lib/gprpp/global_config_generic.h',
'src/core/lib/gprpp/host_port.h',
'src/core/lib/gprpp/manual_constructor.h',
+ 'src/core/lib/gprpp/match.h',
'src/core/lib/gprpp/memory.h',
'src/core/lib/gprpp/mpscq.h',
'src/core/lib/gprpp/orphanable.h',
+ 'src/core/lib/gprpp/overload.h',
'src/core/lib/gprpp/ref_counted.h',
'src/core/lib/gprpp/ref_counted_ptr.h',
'src/core/lib/gprpp/stat.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 89a3c7bca58..66740c1f72e 100644
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -1006,10 +1006,12 @@ Gem::Specification.new do |s|
s.files += %w( src/core/lib/gprpp/host_port.cc )
s.files += %w( src/core/lib/gprpp/host_port.h )
s.files += %w( src/core/lib/gprpp/manual_constructor.h )
+ s.files += %w( src/core/lib/gprpp/match.h )
s.files += %w( src/core/lib/gprpp/memory.h )
s.files += %w( src/core/lib/gprpp/mpscq.cc )
s.files += %w( src/core/lib/gprpp/mpscq.h )
s.files += %w( src/core/lib/gprpp/orphanable.h )
+ s.files += %w( src/core/lib/gprpp/overload.h )
s.files += %w( src/core/lib/gprpp/ref_counted.h )
s.files += %w( src/core/lib/gprpp/ref_counted_ptr.h )
s.files += %w( src/core/lib/gprpp/stat.h )
diff --git a/package.xml b/package.xml
index 12a93079e37..fa5ad41b4dd 100644
--- a/package.xml
+++ b/package.xml
@@ -986,10 +986,12 @@
+
+
diff --git a/src/core/lib/avl/avl.h b/src/core/lib/avl/avl.h
index 9771d845a9f..a1712a36071 100644
--- a/src/core/lib/avl/avl.h
+++ b/src/core/lib/avl/avl.h
@@ -22,6 +22,8 @@
#include
#include
+#include "absl/container/inlined_vector.h"
+
namespace grpc_core {
template
@@ -32,8 +34,12 @@ class AVL {
AVL Add(K key, V value) const {
return AVL(AddKey(root_, std::move(key), std::move(value)));
}
- AVL Remove(const K& key) const { return AVL(RemoveKey(root_, key)); }
- const V* Lookup(const K& key) const {
+ template
+ AVL Remove(const SomethingLikeK& key) const {
+ return AVL(RemoveKey(root_, key));
+ }
+ template
+ const V* Lookup(const SomethingLikeK& key) const {
NodePtr n = Get(root_, key);
return n ? &n->kv.second : nullptr;
}
@@ -50,7 +56,36 @@ class AVL {
ForEachImpl(root_.get(), std::forward(f));
}
- bool SameIdentity(AVL avl) const { return root_ == avl.root_; }
+ bool SameIdentity(const AVL& avl) const { return root_ == avl.root_; }
+
+ bool operator==(const AVL& other) const {
+ Iterator a(root_);
+ Iterator b(other.root_);
+ for (;;) {
+ Node* p = a.current();
+ Node* q = b.current();
+ if (p == nullptr) return q == nullptr;
+ if (q == nullptr) return false;
+ if (p->kv != q->kv) return false;
+ a.MoveNext();
+ b.MoveNext();
+ }
+ }
+
+ bool operator<(const AVL& other) const {
+ Iterator a(root_);
+ Iterator b(other.root_);
+ for (;;) {
+ Node* p = a.current();
+ Node* q = b.current();
+ if (p == nullptr) return q != nullptr;
+ if (q == nullptr) return false;
+ if (p->kv < q->kv) return true;
+ if (p->kv != q->kv) return false;
+ a.MoveNext();
+ b.MoveNext();
+ }
+ }
private:
struct Node;
@@ -68,6 +103,32 @@ class AVL {
};
NodePtr root_;
+ class Iterator {
+ public:
+ explicit Iterator(const NodePtr& root) {
+ auto* n = root.get();
+ while (n != nullptr) {
+ stack_.push_back(n);
+ n = n->left.get();
+ }
+ }
+ Node* current() const { return stack_.empty() ? nullptr : stack_.back(); }
+ void MoveNext() {
+ auto* n = stack_.back();
+ stack_.pop_back();
+ if (n->right != nullptr) {
+ n = n->right.get();
+ while (n != nullptr) {
+ stack_.push_back(n);
+ n = n->left.get();
+ }
+ }
+ }
+
+ private:
+ absl::InlinedVector stack_;
+ };
+
explicit AVL(NodePtr root) : root_(std::move(root)) {}
template
@@ -86,7 +147,8 @@ class AVL {
1 + std::max(Height(left), Height(right)));
}
- static NodePtr Get(const NodePtr& node, const K& key) {
+ template
+ static NodePtr Get(const NodePtr& node, const SomethingLikeK& key) {
if (node == nullptr) {
return nullptr;
}
@@ -198,7 +260,8 @@ class AVL {
return node;
}
- static NodePtr RemoveKey(const NodePtr& node, const K& key) {
+ template
+ static NodePtr RemoveKey(const NodePtr& node, const SomethingLikeK& key) {
if (node == nullptr) {
return nullptr;
}
diff --git a/src/core/lib/channel/channel_args.cc b/src/core/lib/channel/channel_args.cc
index ab256024280..1866f452bd2 100644
--- a/src/core/lib/channel/channel_args.cc
+++ b/src/core/lib/channel/channel_args.cc
@@ -37,6 +37,108 @@
#include "src/core/lib/gpr/string.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/match.h"
+
+namespace {
+
+int PointerCompare(void* a_ptr, const grpc_arg_pointer_vtable* a_vtable,
+ void* b_ptr, const grpc_arg_pointer_vtable* b_vtable) {
+ int c = grpc_core::QsortCompare(a_ptr, b_ptr);
+ if (c == 0) return 0;
+ c = grpc_core::QsortCompare(a_vtable, b_vtable);
+ if (c != 0) return c;
+ return a_vtable->cmp(a_ptr, b_ptr);
+}
+
+} // namespace
+
+namespace grpc_core {
+
+bool ChannelArgs::Pointer::operator==(const Pointer& rhs) const {
+ return PointerCompare(p_, vtable_, rhs.p_, rhs.vtable_) == 0;
+}
+
+bool ChannelArgs::Pointer::operator<(const Pointer& rhs) const {
+ return PointerCompare(p_, vtable_, rhs.p_, rhs.vtable_) < 0;
+}
+
+ChannelArgs::ChannelArgs() = default;
+
+ChannelArgs ChannelArgs::Set(grpc_arg arg) const {
+ switch (arg.type) {
+ case GRPC_ARG_INTEGER:
+ return Set(arg.key, arg.value.integer);
+ case GRPC_ARG_STRING:
+ if (arg.value.string != nullptr) return Set(arg.key, arg.value.string);
+ return Set(arg.key, "");
+ case GRPC_ARG_POINTER:
+ return Set(arg.key,
+ Pointer(arg.value.pointer.vtable->copy(arg.value.pointer.p),
+ arg.value.pointer.vtable));
+ }
+ GPR_UNREACHABLE_CODE(return ChannelArgs());
+}
+
+ChannelArgs ChannelArgs::FromC(const grpc_channel_args* args) {
+ ChannelArgs result;
+ if (args != nullptr) {
+ for (size_t i = 0; i < args->num_args; i++) {
+ result = result.Set(args->args[i]);
+ }
+ }
+ return result;
+}
+
+const grpc_channel_args* ChannelArgs::ToC() const {
+ std::vector c_args;
+ args_.ForEach([&c_args](const std::string& key, const Value& value) {
+ char* name = const_cast(key.c_str());
+ c_args.push_back(Match(
+ value,
+ [name](int i) { return grpc_channel_arg_integer_create(name, i); },
+ [name](const std::string& s) {
+ return grpc_channel_arg_string_create(name,
+ const_cast(s.c_str()));
+ },
+ [name](const Pointer& p) {
+ return grpc_channel_arg_pointer_create(name, p.c_pointer(),
+ p.c_vtable());
+ }));
+ });
+ return grpc_channel_args_copy_and_add(nullptr, c_args.data(), c_args.size());
+}
+
+ChannelArgs ChannelArgs::Set(absl::string_view key, Value value) const {
+ return ChannelArgs(args_.Add(std::string(key), std::move(value)));
+}
+
+ChannelArgs ChannelArgs::Remove(absl::string_view key) const {
+ return ChannelArgs(args_.Remove(key));
+}
+
+absl::optional ChannelArgs::GetInt(absl::string_view name) const {
+ auto* v = Get(name);
+ if (v == nullptr) return absl::nullopt;
+ if (!absl::holds_alternative(*v)) return absl::nullopt;
+ return absl::get(*v);
+}
+
+absl::optional ChannelArgs::GetString(
+ absl::string_view name) const {
+ auto* v = Get(name);
+ if (v == nullptr) return absl::nullopt;
+ if (!absl::holds_alternative(*v)) return absl::nullopt;
+ return absl::get(*v);
+}
+
+void* ChannelArgs::GetVoidPointer(absl::string_view name) const {
+ auto* v = Get(name);
+ if (v == nullptr) return nullptr;
+ if (!absl::holds_alternative(*v)) return nullptr;
+ return absl::get(*v).c_pointer();
+}
+
+} // namespace grpc_core
static grpc_arg copy_arg(const grpc_arg* src) {
grpc_arg dst;
@@ -156,16 +258,8 @@ static int cmp_arg(const grpc_arg* a, const grpc_arg* b) {
case GRPC_ARG_INTEGER:
return grpc_core::QsortCompare(a->value.integer, b->value.integer);
case GRPC_ARG_POINTER:
- c = grpc_core::QsortCompare(a->value.pointer.p, b->value.pointer.p);
- if (c != 0) {
- c = grpc_core::QsortCompare(a->value.pointer.vtable,
- b->value.pointer.vtable);
- if (c == 0) {
- c = a->value.pointer.vtable->cmp(a->value.pointer.p,
- b->value.pointer.p);
- }
- }
- return c;
+ return PointerCompare(a->value.pointer.p, a->value.pointer.vtable,
+ b->value.pointer.p, b->value.pointer.vtable);
}
GPR_UNREACHABLE_CODE(return 0);
}
@@ -369,25 +463,11 @@ std::string grpc_channel_args_string(const grpc_channel_args* args) {
}
namespace grpc_core {
-const grpc_channel_args* RemoveGrpcInternalArgs(const grpc_channel_args* src) {
- if (src == nullptr) return nullptr;
- // Create result.
- grpc_channel_args* dst =
- static_cast(gpr_malloc(sizeof(grpc_channel_args)));
- dst->args =
- static_cast(gpr_malloc(sizeof(grpc_arg) * src->num_args));
- dst->num_args = 0;
- for (size_t i = 0; i < src->num_args; ++i) {
- if (absl::StartsWith(src->args[i].key, "grpc.internal.")) continue;
- dst->args[dst->num_args++] = copy_arg(&src->args[i]);
- }
- return dst;
-}
-
-const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src) {
- if (src == nullptr) return nullptr;
- std::map values;
- std::map> concatenated_values;
+ChannelArgs ChannelArgsBuiltinPrecondition(const grpc_channel_args* src) {
+ if (src == nullptr) return ChannelArgs();
+ ChannelArgs output;
+ std::map>
+ concatenated_values;
for (size_t i = 0; i < src->num_args; i++) {
absl::string_view key = src->args[i].key;
// User-agent strings were traditionally multi-valued and concatenated.
@@ -401,46 +481,23 @@ const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src) {
concatenated_values[key].push_back(src->args[i].value.string);
}
continue;
+ } else if (absl::StartsWith(key, "grpc.internal.")) {
+ continue;
}
- auto it = values.find(key);
- if (it == values.end()) {
- values[key] = &src->args[i];
+ if (!output.Contains(key)) {
+ output = output.Set(src->args[i]);
} else {
// Traditional grpc_channel_args_find behavior was to pick the first
// value.
// For compatibility with existing users, we will do the same here.
}
}
- if (values.size() + concatenated_values.size() == src->num_args) {
- return grpc_channel_args_copy(src);
- }
// Concatenate the concatenated values.
- std::map concatenated_values_str;
for (const auto& concatenated_value : concatenated_values) {
- concatenated_values_str[concatenated_value.first] =
- absl::StrJoin(concatenated_value.second, " ");
+ output = output.Set(concatenated_value.first,
+ absl::StrJoin(concatenated_value.second, " "));
}
- // Create the result
- std::vector argv;
- argv.reserve(values.size());
- for (const auto& a : values) {
- argv.push_back(*a.second);
- }
- for (const auto& a : concatenated_values_str) {
- argv.push_back(
- grpc_channel_arg_string_create(const_cast(a.first.data()),
- const_cast(a.second.c_str())));
- }
- grpc_channel_args args = {argv.size(), argv.data()};
- // Log that we're mutating things
- gpr_log(GPR_INFO,
- "Uniquification pass on channel args is mutating them: {%s} is being "
- "changed to {%s}",
- grpc_channel_args_string(src).c_str(),
- grpc_channel_args_string(&args).c_str());
- // Return the result (note we need to copy because we're borrowing the args
- // from src still!)
- return grpc_channel_args_copy(&args);
+ return output;
}
} // namespace grpc_core
diff --git a/src/core/lib/channel/channel_args.h b/src/core/lib/channel/channel_args.h
index 48007f1e84f..1cd56ac3429 100644
--- a/src/core/lib/channel/channel_args.h
+++ b/src/core/lib/channel/channel_args.h
@@ -23,12 +23,175 @@
#include
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "absl/types/variant.h"
+
#include
+#include "src/core/lib/avl/avl.h"
+#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/surface/channel_stack_type.h"
// Channel args are intentionally immutable, to avoid the need for locking.
+namespace grpc_core {
+
+// Define a traits object for vtable lookup - allows us to integrate with
+// existing code easily (just define the trait!) and allows some magic in
+// ChannelArgs to automatically derive a vtable from a T*.
+// To participate as a pointer, instances should expose the function:
+// // Gets the vtable for this type
+// static const grpc_channel_arg_vtable* VTable();
+// // Performs any mutations required for channel args to own a pointer
+// // Only needed if ChannelArgs::Set is to be called with a raw pointer.
+// static void* TakeUnownedPointer(T* p);
+template
+struct ChannelArgTypeTraits;
+
+template
+struct ChannelArgTypeTraits<
+ T, absl::enable_if_t, T>::value, void>> {
+ static const grpc_arg_pointer_vtable* VTable() {
+ static const grpc_arg_pointer_vtable tbl = {
+ // copy
+ [](void* p) -> void* { return static_cast(p)->Ref().release(); },
+ // destroy
+ [](void* p) { static_cast(p)->Unref(); },
+ // compare
+ [](void* p1, void* p2) {
+ return QsortCompare(*static_cast(p1),
+ *static_cast(p2));
+ },
+ };
+ return &tbl;
+ };
+};
+
+class ChannelArgs {
+ public:
+ class Pointer {
+ public:
+ Pointer(void* p, const grpc_arg_pointer_vtable* vtable)
+ : p_(p), vtable_(vtable == nullptr ? EmptyVTable() : vtable) {}
+ ~Pointer() { vtable_->destroy(p_); }
+
+ Pointer(const Pointer& other)
+ : p_(other.vtable_->copy(other.p_)), vtable_(other.vtable_) {}
+ Pointer& operator=(Pointer other) {
+ std::swap(p_, other.p_);
+ std::swap(vtable_, other.vtable_);
+ return *this;
+ }
+ Pointer(Pointer&& other) noexcept : p_(other.p_), vtable_(other.vtable_) {
+ other.p_ = nullptr;
+ other.vtable_ = EmptyVTable();
+ }
+ Pointer& operator=(Pointer&& other) noexcept {
+ std::swap(p_, other.p_);
+ std::swap(vtable_, other.vtable_);
+ return *this;
+ }
+
+ bool operator==(const Pointer& rhs) const;
+ bool operator<(const Pointer& rhs) const;
+ bool operator!=(const Pointer& rhs) const { return !(*this == rhs); }
+
+ void* c_pointer() const { return p_; }
+
+ const grpc_arg_pointer_vtable* c_vtable() const { return vtable_; }
+
+ private:
+ static const grpc_arg_pointer_vtable* EmptyVTable() {
+ static const grpc_arg_pointer_vtable vtable = {
+ // copy
+ [](void* p) { return p; },
+ // destroy
+ [](void*) {},
+ // cmp
+ [](void* p1, void* p2) -> int { return QsortCompare(p1, p2); },
+ };
+ return &vtable;
+ }
+
+ void* p_;
+ const grpc_arg_pointer_vtable* vtable_;
+ };
+ using Value = absl::variant;
+
+ ChannelArgs();
+
+ static ChannelArgs FromC(const grpc_channel_args* args);
+ // Construct a new grpc_channel_args struct which the caller will own.
+ // It should be destroyed with grpc_channel_args_destroy.
+ const grpc_channel_args* ToC() const;
+
+ const Value* Get(absl::string_view name) const { return args_.Lookup(name); }
+ GRPC_MUST_USE_RESULT ChannelArgs Set(absl::string_view name,
+ Value value) const;
+ GRPC_MUST_USE_RESULT ChannelArgs Set(grpc_arg arg) const;
+ template
+ GRPC_MUST_USE_RESULT absl::enable_if_t<
+ std::is_same::vtable())>::value,
+ ChannelArgs>
+ Set(absl::string_view name, T* value) const {
+ return Set(name, Pointer(ChannelArgTypeTraits::TakeUnownedPointer(value),
+ ChannelArgTypeTraits::VTable()));
+ }
+ template
+ GRPC_MUST_USE_RESULT absl::enable_if_t<
+ std::is_same::VTable())>::value,
+ ChannelArgs>
+ Set(absl::string_view name, RefCountedPtr value) const {
+ return Set(name,
+ Pointer(value.release(), ChannelArgTypeTraits::VTable()));
+ }
+ GRPC_MUST_USE_RESULT ChannelArgs Remove(absl::string_view name) const;
+ bool Contains(absl::string_view name) const { return Get(name) != nullptr; }
+
+ absl::optional GetInt(absl::string_view name) const;
+ absl::optional GetString(absl::string_view name) const;
+ void* GetVoidPointer(absl::string_view name) const;
+ template
+ T* GetPointer(absl::string_view name) const {
+ return static_cast(GetVoidPointer(name));
+ }
+
+ // Object based get/set.
+ // Deal with the common case that we set a pointer to an object under
+ // the same name in every usage.
+ // Expects ChannelArgTypeTraits to exist for T, and T to expose:
+ // static string_view ChannelArgName();
+ template
+ GRPC_MUST_USE_RESULT ChannelArgs SetObject(T* p) const {
+ return Set(T::ChannelArgName(), p);
+ }
+ template
+ GRPC_MUST_USE_RESULT ChannelArgs SetObject(RefCountedPtr p) const {
+ return Set(T::ChannelArgName(), std::move(p));
+ }
+ template
+ T* GetObject() {
+ return GetPointer(T::ChannelArgName());
+ }
+
+ bool operator<(const ChannelArgs& other) const { return args_ < other.args_; }
+ bool operator==(const ChannelArgs& other) const {
+ return args_ == other.args_;
+ }
+
+ private:
+ explicit ChannelArgs(AVL args) : args_(std::move(args)) {}
+
+ AVL args_;
+};
+
+} // namespace grpc_core
+
/** Copy the arguments in \a src into a new instance */
grpc_channel_args* grpc_channel_args_copy(const grpc_channel_args* src);
@@ -120,15 +283,10 @@ grpc_arg grpc_channel_arg_pointer_create(char* name, void* value,
std::string grpc_channel_args_string(const grpc_channel_args* args);
namespace grpc_core {
-/** Remove any channel args prefixed with 'grpc.internal.'
- * These are used for internal implementation details and are not intended to
- * be exposed to users.
- * Returns a new channel args instance.
- * Does not take ownership of \a src.
- * Should be called by any public API that receives channel args. */
-const grpc_channel_args* RemoveGrpcInternalArgs(const grpc_channel_args* src);
-/** Ensure no duplicate channel args, in preparation for moving to a map<> */
-const grpc_channel_args* UniquifyChannelArgKeys(const grpc_channel_args* src);
+// Ensure no duplicate channel args (with some backwards compatibility hacks).
+// Eliminate any grpc.internal.* args.
+// Return a C++ object.
+ChannelArgs ChannelArgsBuiltinPrecondition(const grpc_channel_args* src);
} // namespace grpc_core
// Takes ownership of the old_args
diff --git a/src/core/lib/channel/channel_args_preconditioning.cc b/src/core/lib/channel/channel_args_preconditioning.cc
index 640ca58b9da..3e431a97579 100644
--- a/src/core/lib/channel/channel_args_preconditioning.cc
+++ b/src/core/lib/channel/channel_args_preconditioning.cc
@@ -25,10 +25,6 @@ void ChannelArgsPreconditioning::Builder::RegisterStage(Stage stage) {
}
ChannelArgsPreconditioning ChannelArgsPreconditioning::Builder::Build() {
- // TODO(ctiller): should probably make this registered too.
- stages_.emplace_back(RemoveGrpcInternalArgs);
- stages_.emplace_back(UniquifyChannelArgKeys);
-
ChannelArgsPreconditioning preconditioning;
preconditioning.stages_ = std::move(stages_);
return preconditioning;
@@ -36,13 +32,11 @@ ChannelArgsPreconditioning ChannelArgsPreconditioning::Builder::Build() {
const grpc_channel_args* ChannelArgsPreconditioning::PreconditionChannelArgs(
const grpc_channel_args* args) const {
- const grpc_channel_args* owned_args = nullptr;
+ ChannelArgs channel_args = ChannelArgsBuiltinPrecondition(args);
for (auto& stage : stages_) {
- args = stage(args);
- grpc_channel_args_destroy(owned_args);
- owned_args = args;
+ channel_args = stage(std::move(channel_args));
}
- return args;
+ return channel_args.ToC();
}
} // namespace grpc_core
diff --git a/src/core/lib/channel/channel_args_preconditioning.h b/src/core/lib/channel/channel_args_preconditioning.h
index 224399fb549..06a4b5e78fc 100644
--- a/src/core/lib/channel/channel_args_preconditioning.h
+++ b/src/core/lib/channel/channel_args_preconditioning.h
@@ -33,8 +33,7 @@ class ChannelArgsPreconditioning {
// Take channel args and mutate them.
// Does not take ownership of the channel args passed in.
// Returns a new channel args object that is owned by the caller.
- using Stage =
- std::function;
+ using Stage = std::function;
class Builder {
public:
diff --git a/src/core/lib/resource_quota/api.cc b/src/core/lib/resource_quota/api.cc
index efbd1737a55..2cad657f464 100644
--- a/src/core/lib/resource_quota/api.cc
+++ b/src/core/lib/resource_quota/api.cc
@@ -20,6 +20,7 @@
#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/iomgr/exec_ctx.h"
+#include "src/core/lib/resource_quota/resource_quota.h"
namespace grpc_core {
@@ -30,30 +31,13 @@ ResourceQuotaRefPtr ResourceQuotaFromChannelArgs(
->Ref();
}
-namespace {
-grpc_arg MakeArg(ResourceQuota* quota) {
- return grpc_channel_arg_pointer_create(
- const_cast(GRPC_ARG_RESOURCE_QUOTA), quota,
- grpc_resource_quota_arg_vtable());
-}
-
-const grpc_channel_args* EnsureResourceQuotaInChannelArgs(
- const grpc_channel_args* args) {
- const grpc_arg* existing =
- grpc_channel_args_find(args, GRPC_ARG_RESOURCE_QUOTA);
- if (existing != nullptr && existing->type == GRPC_ARG_POINTER &&
- existing->value.pointer.p != nullptr) {
- return grpc_channel_args_copy(args);
- }
+ChannelArgs EnsureResourceQuotaInChannelArgs(ChannelArgs args) {
+ if (args.GetObject() != nullptr) return args;
// If there's no existing quota, add it to the default one - shared between
// all channel args declared thusly. This prevents us from accidentally not
// sharing subchannels due to their channel args not specifying a quota.
- const char* remove[] = {GRPC_ARG_RESOURCE_QUOTA};
- auto new_arg = MakeArg(ResourceQuota::Default().get());
- return grpc_channel_args_copy_and_add_and_remove(args, remove, 1, &new_arg,
- 1);
+ return args.SetObject(ResourceQuota::Default());
}
-} // namespace
void RegisterResourceQuota(CoreConfiguration::Builder* builder) {
builder->channel_args_preconditioning()->RegisterStage(
@@ -63,16 +47,7 @@ void RegisterResourceQuota(CoreConfiguration::Builder* builder) {
} // namespace grpc_core
extern "C" const grpc_arg_pointer_vtable* grpc_resource_quota_arg_vtable() {
- static const grpc_arg_pointer_vtable vtable = {
- // copy
- [](void* p) -> void* {
- return static_cast(p)->Ref().release();
- },
- // destroy
- [](void* p) { static_cast(p)->Unref(); },
- // compare
- [](void* p, void* q) { return grpc_core::QsortCompare(p, q); }};
- return &vtable;
+ return grpc_core::ChannelArgTypeTraits::VTable();
}
extern "C" grpc_resource_quota* grpc_resource_quota_create(const char* name) {
diff --git a/src/core/lib/resource_quota/resource_quota.h b/src/core/lib/resource_quota/resource_quota.h
index 28a6156ea59..f366e4fcb83 100644
--- a/src/core/lib/resource_quota/resource_quota.h
+++ b/src/core/lib/resource_quota/resource_quota.h
@@ -37,6 +37,8 @@ class ResourceQuota : public RefCounted,
ResourceQuota(const ResourceQuota&) = delete;
ResourceQuota& operator=(const ResourceQuota&) = delete;
+ static absl::string_view ChannelArgName() { return GRPC_ARG_RESOURCE_QUOTA; }
+
MemoryQuotaRefPtr memory_quota() { return memory_quota_; }
const RefCountedPtr& thread_quota() { return thread_quota_; }
@@ -44,6 +46,8 @@ class ResourceQuota : public RefCounted,
// The default global resource quota
static ResourceQuotaRefPtr Default();
+ bool operator<(const ResourceQuota& other) const { return this < &other; }
+
private:
MemoryQuotaRefPtr memory_quota_;
RefCountedPtr thread_quota_;
diff --git a/test/core/avl/avl_fuzzer.cc b/test/core/avl/avl_fuzzer.cc
index 109f64fe2be..7fb5f74f72e 100644
--- a/test/core/avl/avl_fuzzer.cc
+++ b/test/core/avl/avl_fuzzer.cc
@@ -23,29 +23,27 @@ namespace grpc_core {
class Fuzzer {
public:
- void Run(const avl_fuzzer::Msg& msg) {
- CheckEqual();
- for (const auto& action : msg.actions()) {
- switch (action.action_case()) {
- case avl_fuzzer::Action::kSet:
- avl_ = avl_.Add(action.key(), action.set());
- map_[action.key()] = action.set();
- break;
- case avl_fuzzer::Action::kDel:
- avl_ = avl_.Remove(action.key());
- map_.erase(action.key());
- break;
- case avl_fuzzer::Action::kGet: {
- auto* p = avl_.Lookup(action.key());
- auto it = map_.find(action.key());
- if (it == map_.end() && p != nullptr) abort();
- if (it != map_.end() && p == nullptr) abort();
- if (it != map_.end() && it->second != *p) abort();
- } break;
- case avl_fuzzer::Action::ACTION_NOT_SET:
- break;
- }
- CheckEqual();
+ Fuzzer() { CheckEqual(); }
+ ~Fuzzer() { CheckEqual(); }
+ void Run(const avl_fuzzer::Action& action) {
+ switch (action.action_case()) {
+ case avl_fuzzer::Action::kSet:
+ avl_ = avl_.Add(action.key(), action.set());
+ map_[action.key()] = action.set();
+ break;
+ case avl_fuzzer::Action::kDel:
+ avl_ = avl_.Remove(action.key());
+ map_.erase(action.key());
+ break;
+ case avl_fuzzer::Action::kGet: {
+ auto* p = avl_.Lookup(action.key());
+ auto it = map_.find(action.key());
+ if (it == map_.end() && p != nullptr) abort();
+ if (it != map_.end() && p == nullptr) abort();
+ if (it != map_.end() && it->second != *p) abort();
+ } break;
+ case avl_fuzzer::Action::ACTION_NOT_SET:
+ break;
}
}
@@ -65,8 +63,38 @@ class Fuzzer {
std::map map_;
};
+template
+AVL AvlFromProto(const RepeatedField& p) {
+ AVL a;
+ for (const auto& kv : p) {
+ a = a.Add(kv.key(), kv.value());
+ }
+ return a;
+}
+
+template
+std::map MapFromProto(const RepeatedField& p) {
+ std::map a;
+ for (const auto& kv : p) {
+ a[kv.key()] = kv.value();
+ }
+ return a;
+}
+
} // namespace grpc_core
DEFINE_PROTO_FUZZER(const avl_fuzzer::Msg& msg) {
- grpc_core::Fuzzer().Run(msg);
+ grpc_core::Fuzzer fuzzer;
+ for (const auto& action : msg.actions()) {
+ grpc_core::Fuzzer().Run(action);
+ }
+
+ for (const auto& cmp : msg.compares()) {
+ auto left_avl = grpc_core::AvlFromProto(cmp.left());
+ auto left_map = grpc_core::MapFromProto(cmp.left());
+ auto right_avl = grpc_core::AvlFromProto(cmp.right());
+ auto right_map = grpc_core::MapFromProto(cmp.right());
+ if ((left_avl == right_avl) != (left_map == right_map)) abort();
+ if ((left_avl < right_avl) != (left_map < right_map)) abort();
+ }
}
diff --git a/test/core/avl/avl_fuzzer.proto b/test/core/avl/avl_fuzzer.proto
index 74a613c2a8b..ec05fe313d2 100644
--- a/test/core/avl/avl_fuzzer.proto
+++ b/test/core/avl/avl_fuzzer.proto
@@ -27,6 +27,17 @@ message Action {
}
}
+message KeyValue {
+ int32 key = 1;
+ int32 value = 2;
+}
+
+message Compares {
+ repeated KeyValue left = 1;
+ repeated KeyValue right = 2;
+}
+
message Msg {
repeated Action actions = 2;
+ repeated Compares compares = 3;
}
diff --git a/test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907 b/test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907
new file mode 100644
index 00000000000..cf46495b8aa
--- /dev/null
+++ b/test/core/avl/avl_fuzzer_corpus/crash-060a9a897130ba7bb2f4313daa604c47f7c7c907
@@ -0,0 +1,9 @@
+actions {
+ del {
+ }
+}
+compares {
+ left {
+ key: 50397184
+ }
+}
diff --git a/test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360 b/test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360
new file mode 100644
index 00000000000..c621adbddce
--- /dev/null
+++ b/test/core/avl/avl_fuzzer_corpus/crash-1fbe8edb82f9a7aa4c2dffe4a6eaa40c34b1e360
@@ -0,0 +1,5 @@
+compares {
+ right {
+ key: 805306368
+ }
+}
diff --git a/test/core/channel/BUILD b/test/core/channel/BUILD
index f91e914693e..6b4e37add48 100644
--- a/test/core/channel/BUILD
+++ b/test/core/channel/BUILD
@@ -21,6 +21,7 @@ licenses(["notice"])
grpc_cc_test(
name = "channel_args_test",
srcs = ["channel_args_test.cc"],
+ external_deps = ["gtest"],
language = "C++",
uses_polling = False,
deps = [
diff --git a/test/core/channel/channel_args_test.cc b/test/core/channel/channel_args_test.cc
index efcf5047cc1..0eb4f1abaab 100644
--- a/test/core/channel/channel_args_test.cc
+++ b/test/core/channel/channel_args_test.cc
@@ -20,6 +20,8 @@
#include
+#include
+
#include
#include
#include
@@ -27,11 +29,101 @@
#include "src/core/lib/channel/channel_stack.h"
#include "src/core/lib/gpr/useful.h"
+#include "src/core/lib/gprpp/ref_counted.h"
+#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/surface/channel.h"
#include "test/core/util/test_config.h"
-static void test_create(void) {
+namespace grpc_core {
+
+TEST(ChannelArgsTest, Noop) { ChannelArgs(); }
+
+TEST(ChannelArgsTest, SetGetRemove) {
+ const grpc_arg_pointer_vtable malloc_vtable = {
+ // copy
+ [](void* p) { return p; },
+ // destroy
+ [](void*) {},
+ // equal
+ [](void* p1, void* p2) { return QsortCompare(p1, p2); },
+ };
+ void* ptr = gpr_malloc(42);
+
+ ChannelArgs a;
+ ChannelArgs b = a.Set("answer", 42);
+ ChannelArgs c = b.Set("foo", "bar");
+ ChannelArgs d = c.Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable));
+ ChannelArgs e = d.Set("alpha", "beta");
+ ChannelArgs f = e.Remove("answer");
+ EXPECT_EQ(a.Get("answer"), nullptr);
+ EXPECT_EQ(*b.Get("answer"), ChannelArgs::Value(42));
+ EXPECT_EQ(*c.Get("answer"), ChannelArgs::Value(42));
+ EXPECT_EQ(c.GetInt("answer"), 42);
+ EXPECT_EQ(c.GetString("answer"), absl::nullopt);
+ EXPECT_EQ(f.Get("answer"), nullptr);
+ EXPECT_EQ(*c.Get("foo"), ChannelArgs::Value("bar"));
+ EXPECT_EQ(c.GetString("foo"), "bar");
+ EXPECT_EQ(c.GetString("answer"), absl::nullopt);
+ EXPECT_EQ(*d.Get("ptr"),
+ ChannelArgs::Value(ChannelArgs::Pointer(ptr, &malloc_vtable)));
+ EXPECT_EQ(*e.Get("alpha"), ChannelArgs::Value("beta"));
+ gpr_free(ptr);
+}
+
+TEST(ChannelArgsTest, StoreRefCountedPtr) {
+ struct Test : public RefCounted {
+ explicit Test(int n) : n(n) {}
+ int n;
+ bool operator<(const Test& rhs) const { return n < rhs.n; }
+ };
+ auto p = MakeRefCounted(123);
+
+ ChannelArgs a;
+ a = a.Set("test", std::move(p));
+ EXPECT_EQ(a.GetPointer("test")->n, 123);
+}
+
+TEST(ChannelArgsTest, ObjectApi) {
+ struct MyFancyObject : public RefCounted {
+ explicit MyFancyObject(int n) : n(n) {}
+ static absl::string_view ChannelArgName() {
+ return "grpc.internal.my-fancy-object";
+ }
+ int n;
+ bool operator<(const MyFancyObject& rhs) const { return n < rhs.n; }
+ };
+ auto p = MakeRefCounted(42);
+ ChannelArgs a;
+ a = a.SetObject(std::move(p));
+ EXPECT_EQ(a.GetObject()->n, 42);
+}
+
+TEST(ChannelArgsTest, ToAndFromC) {
+ const grpc_arg_pointer_vtable malloc_vtable = {
+ // copy
+ [](void* p) { return p; },
+ // destroy
+ [](void*) {},
+ // equal
+ [](void* p1, void* p2) { return QsortCompare(p1, p2); },
+ };
+ void* ptr = gpr_malloc(42);
+ ChannelArgs a = ChannelArgs()
+ .Set("answer", 42)
+ .Set("foo", "bar")
+ .Set("ptr", ChannelArgs::Pointer(ptr, &malloc_vtable))
+ .Set("alpha", "beta");
+ const grpc_channel_args* c = a.ToC();
+ ChannelArgs b = ChannelArgs::FromC(c);
+ grpc_channel_args_destroy(c);
+ EXPECT_EQ(a, b);
+ gpr_free(ptr);
+}
+
+} // namespace grpc_core
+
+TEST(GrpcChannelArgsTest, Create) {
grpc_core::ExecCtx exec_ctx;
grpc_arg to_add[2];
grpc_channel_args* ch_args;
@@ -80,7 +172,7 @@ static int fake_pointer_cmp(void* a, void* b) {
static const grpc_arg_pointer_vtable fake_pointer_arg_vtable = {
fake_pointer_arg_copy, fake_pointer_arg_destroy, fake_pointer_cmp};
-static void test_channel_create_with_args(void) {
+TEST(GrpcChannelArgsTest, ChannelCreateWithArgs) {
grpc_arg client_a[3];
client_a[0] =
@@ -131,53 +223,7 @@ grpc_channel_args* mutate_channel_args(const char* target,
return new_args;
}
-// Minimal stack should not have client_idle filter
-static bool channel_has_client_idle_filter(grpc_channel* c) {
- grpc_channel_stack* stack = grpc_channel_get_channel_stack(c);
- for (size_t i = 0; i < stack->count; i++) {
- if (strcmp(grpc_channel_stack_element(stack, i)->filter->name,
- "client_idle") == 0) {
- return true;
- }
- }
- return false;
-}
-
-static void test_channel_create_with_global_mutator(void) {
- grpc_channel_args_set_client_channel_creation_mutator(mutate_channel_args);
- // We also add some custom args to make sure the ownership is correct.
- grpc_arg client_a[3];
-
- client_a[0] =
- grpc_channel_arg_integer_create(const_cast("arg_int"), 0);
- client_a[1] = grpc_channel_arg_string_create(
- const_cast("arg_str"), const_cast("arg_str_val"));
- // allocated and adds custom pointer arg
- fake_class* fc = static_cast(gpr_malloc(sizeof(fake_class)));
- fc->foo = 42;
- client_a[2] = grpc_channel_arg_pointer_create(
- const_cast("arg_pointer"), fc, &fake_pointer_arg_vtable);
-
- // creates channels
- grpc_channel_args client_args = {GPR_ARRAY_SIZE(client_a), client_a};
- grpc_channel_credentials* creds = grpc_insecure_credentials_create();
- grpc_channel* c = grpc_channel_create("no_op_mutator", creds, &client_args);
- grpc_channel_credentials_release(creds);
- GPR_ASSERT(channel_has_client_idle_filter(c));
- grpc_channel_destroy(c);
-
- grpc_channel_credentials* another_creds = grpc_insecure_credentials_create();
- c = grpc_channel_create("minimal_stack_mutator", another_creds, &client_args);
- grpc_channel_credentials_release(another_creds);
- GPR_ASSERT(channel_has_client_idle_filter(c) == false);
- grpc_channel_destroy(c);
-
- gpr_free(fc);
- auto mutator = grpc_channel_args_get_client_channel_creation_mutator();
- GPR_ASSERT(mutator == &mutate_channel_args);
-}
-
-static void test_server_create_with_args(void) {
+TEST(GrpcChannelArgsTest, TestServerCreateWithArgs) {
grpc_arg server_a[3];
// adds integer arg
@@ -207,14 +253,10 @@ static void test_server_create_with_args(void) {
}
int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
grpc::testing::TestEnvironment env(argc, argv);
grpc_init();
- test_create();
- test_channel_create_with_args();
- test_server_create_with_args();
- // This has to be the last test.
- // TODO(markdroth): re-enable this test once client_idle is re-enabled
- // test_channel_create_with_global_mutator();
+ auto r = RUN_ALL_TESTS();
grpc_shutdown();
- return 0;
+ return r;
}
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index 3f558f77388..77247126804 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -1985,10 +1985,12 @@ src/core/lib/gprpp/global_config_generic.h \
src/core/lib/gprpp/host_port.cc \
src/core/lib/gprpp/host_port.h \
src/core/lib/gprpp/manual_constructor.h \
+src/core/lib/gprpp/match.h \
src/core/lib/gprpp/memory.h \
src/core/lib/gprpp/mpscq.cc \
src/core/lib/gprpp/mpscq.h \
src/core/lib/gprpp/orphanable.h \
+src/core/lib/gprpp/overload.h \
src/core/lib/gprpp/ref_counted.h \
src/core/lib/gprpp/ref_counted_ptr.h \
src/core/lib/gprpp/stat.h \
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index ea597fb1f74..0f2db1932da 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -1779,10 +1779,12 @@ src/core/lib/gprpp/global_config_generic.h \
src/core/lib/gprpp/host_port.cc \
src/core/lib/gprpp/host_port.h \
src/core/lib/gprpp/manual_constructor.h \
+src/core/lib/gprpp/match.h \
src/core/lib/gprpp/memory.h \
src/core/lib/gprpp/mpscq.cc \
src/core/lib/gprpp/mpscq.h \
src/core/lib/gprpp/orphanable.h \
+src/core/lib/gprpp/overload.h \
src/core/lib/gprpp/ref_counted.h \
src/core/lib/gprpp/ref_counted_ptr.h \
src/core/lib/gprpp/stat.h \
diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json
index 1d7be30f956..8d81d9dfcd2 100644
--- a/tools/run_tests/generated/tests.json
+++ b/tools/run_tests/generated/tests.json
@@ -525,30 +525,6 @@
],
"uses_polling": true
},
- {
- "args": [],
- "benchmark": false,
- "ci_platforms": [
- "linux",
- "mac",
- "posix",
- "windows"
- ],
- "cpu_cost": 1.0,
- "exclude_configs": [],
- "exclude_iomgrs": [],
- "flaky": false,
- "gtest": false,
- "language": "c",
- "name": "channel_args_test",
- "platforms": [
- "linux",
- "mac",
- "posix",
- "windows"
- ],
- "uses_polling": false
- },
{
"args": [],
"benchmark": false,
@@ -3303,6 +3279,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": "channel_args_test",
+ "platforms": [
+ "linux",
+ "mac",
+ "posix",
+ "windows"
+ ],
+ "uses_polling": false
+ },
{
"args": [],
"benchmark": false,