[channel] Integrate channel init infrastructure with new call filter infrastructure (#35767)

built on #35766

Closes #35767

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/35767 from ctiller:chan3+1 22cbba7de8
PiperOrigin-RevId: 604446427
pull/35819/head
Craig Tiller 1 year ago committed by Copybara-Service
parent 122a1996ae
commit 3ff53525d1
  1. 1
      src/core/BUILD
  2. 12
      src/core/lib/channel/channel_args.h
  3. 88
      src/core/lib/surface/channel_init.cc
  4. 110
      src/core/lib/surface/channel_init.h
  5. 15
      src/core/lib/transport/call_filters.cc
  6. 229
      src/core/lib/transport/call_filters.h
  7. 58
      test/core/surface/channel_init_test.cc

@ -2858,6 +2858,7 @@ grpc_cc_library(
],
language = "c++",
deps = [
"call_filters",
"channel_args",
"channel_fwd",
"channel_stack_trace",

@ -324,6 +324,18 @@ class ChannelArgs {
const grpc_arg_pointer_vtable* vtable_;
};
// Helper to create a `Pointer` object to an object that is not owned by the
// `ChannelArgs` object. Useful for tests, a code smell for production code.
template <typename T>
static Pointer UnownedPointer(T* p) {
static const grpc_arg_pointer_vtable vtable = {
[](void* p) -> void* { return p; },
[](void*) {},
[](void* p, void* q) { return QsortCompare(p, q); },
};
return Pointer(p, &vtable);
}
class Value {
public:
explicit Value(int n)

@ -104,9 +104,9 @@ ChannelInit::FilterRegistration::ExcludeFromMinimalStack() {
ChannelInit::FilterRegistration& ChannelInit::Builder::RegisterFilter(
grpc_channel_stack_type type, const grpc_channel_filter* filter,
SourceLocation registration_source) {
filters_[type].emplace_back(
std::make_unique<FilterRegistration>(filter, registration_source));
const ChannelFilterVtable* vtable, SourceLocation registration_source) {
filters_[type].emplace_back(std::make_unique<FilterRegistration>(
filter, vtable, registration_source));
return *filters_[type].back();
}
@ -141,7 +141,7 @@ ChannelInit::StackConfig ChannelInit::BuildStackConfig(
GPR_ASSERT(registration->after_.empty());
GPR_ASSERT(registration->before_.empty());
GPR_ASSERT(!registration->before_all_);
terminal_filters.emplace_back(registration->filter_,
terminal_filters.emplace_back(registration->filter_, nullptr,
std::move(registration->predicates_),
registration->registration_source_);
} else {
@ -222,9 +222,10 @@ ChannelInit::StackConfig ChannelInit::BuildStackConfig(
std::vector<Filter> filters;
while (!dependencies.empty()) {
auto filter = take_ready_dependency();
filters.emplace_back(filter,
std::move(filter_to_registration[filter]->predicates_),
filter_to_registration[filter]->registration_source_);
auto* registration = filter_to_registration[filter];
filters.emplace_back(filter, registration->vtable_,
std::move(registration->predicates_),
registration->registration_source_);
for (auto& p : dependencies) {
p.second.erase(filter);
}
@ -405,4 +406,77 @@ bool ChannelInit::CreateStack(ChannelStackBuilder* builder) const {
return true;
}
absl::StatusOr<ChannelInit::StackSegment> ChannelInit::CreateStackSegment(
grpc_channel_stack_type type, const ChannelArgs& args) const {
const auto& stack_config = stack_configs_[type];
std::vector<StackSegment::ChannelFilter> filters;
size_t channel_data_size = 0;
size_t channel_data_alignment = 0;
// Based on predicates build a list of filters to include in this segment.
for (const auto& filter : stack_config.filters) {
if (!filter.CheckPredicates(args)) continue;
if (filter.vtable == nullptr) {
return absl::InvalidArgumentError(
absl::StrCat("Filter ", NameFromChannelFilter(filter.filter),
" has no v3-callstack vtable"));
}
channel_data_alignment =
std::max(channel_data_alignment, filter.vtable->alignment);
if (channel_data_size % filter.vtable->alignment != 0) {
channel_data_size += filter.vtable->alignment -
(channel_data_size % filter.vtable->alignment);
}
filters.push_back({channel_data_size, filter.vtable});
channel_data_size += filter.vtable->size;
}
// Shortcut for empty segments.
if (filters.empty()) return StackSegment();
// Allocate memory for the channel data, initialize channel filters into it.
uint8_t* p = static_cast<uint8_t*>(
gpr_malloc_aligned(channel_data_size, channel_data_alignment));
for (size_t i = 0; i < filters.size(); i++) {
auto r = filters[i].vtable->init(p + filters[i].offset, args);
if (!r.ok()) {
for (size_t j = 0; j < i; j++) {
filters[j].vtable->destroy(p + filters[j].offset);
}
gpr_free_aligned(p);
return r;
}
}
return StackSegment(std::move(filters), p);
}
///////////////////////////////////////////////////////////////////////////////
// ChannelInit::StackSegment
ChannelInit::StackSegment::StackSegment(std::vector<ChannelFilter> filters,
uint8_t* channel_data)
: data_(MakeRefCounted<ChannelData>(std::move(filters), channel_data)) {}
void ChannelInit::StackSegment::AddToCallFilterStack(
CallFilters::StackBuilder& builder) {
if (data_ == nullptr) return;
data_->AddToCallFilterStack(builder);
builder.AddOwnedObject(data_);
};
ChannelInit::StackSegment::ChannelData::ChannelData(
std::vector<ChannelFilter> filters, uint8_t* channel_data)
: filters_(std::move(filters)), channel_data_(channel_data) {}
void ChannelInit::StackSegment::ChannelData::AddToCallFilterStack(
CallFilters::StackBuilder& builder) {
for (const auto& filter : filters_) {
filter.vtable->add_to_stack_builder(channel_data_ + filter.offset, builder);
}
}
ChannelInit::StackSegment::ChannelData::~ChannelData() {
for (const auto& filter : filters_) {
filter.vtable->destroy(channel_data_ + filter.offset);
}
gpr_free_aligned(channel_data_);
}
} // namespace grpc_core

@ -37,6 +37,7 @@
#include "src/core/lib/channel/channel_stack_builder.h"
#include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/surface/channel_stack_type.h"
#include "src/core/lib/transport/call_filters.h"
/// This module provides a way for plugins (and the grpc core library itself)
/// to register mutators for channel stacks.
@ -76,11 +77,26 @@ class ChannelInit {
kCount
};
// Vtable-like data structure for channel data initialization
struct ChannelFilterVtable {
size_t size;
size_t alignment;
absl::Status (*init)(void* data, const ChannelArgs& args);
void (*destroy)(void* data);
void (*add_to_stack_builder)(void* data,
CallFilters::StackBuilder& builder);
};
class FilterRegistration {
public:
// TODO(ctiller): Remove grpc_channel_filter* arg when that can be
// deprecated (once filter stack is removed).
explicit FilterRegistration(const grpc_channel_filter* filter,
const ChannelFilterVtable* vtable,
SourceLocation registration_source)
: filter_(filter), registration_source_(registration_source) {}
: filter_(filter),
vtable_(vtable),
registration_source_(registration_source) {}
FilterRegistration(const FilterRegistration&) = delete;
FilterRegistration& operator=(const FilterRegistration&) = delete;
@ -150,6 +166,7 @@ class ChannelInit {
private:
friend class ChannelInit;
const grpc_channel_filter* const filter_;
const ChannelFilterVtable* const vtable_;
std::vector<const grpc_channel_filter*> after_;
std::vector<const grpc_channel_filter*> before_;
std::vector<InclusionPredicate> predicates_;
@ -166,13 +183,16 @@ class ChannelInit {
// properties of the filter being registered.
// TODO(ctiller): remove in favor of the version that does not mention
// grpc_channel_filter
FilterRegistration& RegisterFilter(grpc_channel_stack_type type,
const grpc_channel_filter* filter,
SourceLocation registration_source = {});
FilterRegistration& RegisterFilter(
grpc_channel_stack_type type, const grpc_channel_filter* filter,
const ChannelFilterVtable* vtable = nullptr,
SourceLocation registration_source = {});
template <typename Filter>
FilterRegistration& RegisterFilter(
grpc_channel_stack_type type, SourceLocation registration_source = {}) {
return RegisterFilter(type, &Filter::kFilter, registration_source);
return RegisterFilter(type, &Filter::kFilter,
VtableForType<Filter>::vtable(),
registration_source);
}
// Register a post processor for the builder.
@ -198,20 +218,70 @@ class ChannelInit {
[static_cast<int>(PostProcessorSlot::kCount)];
};
// A set of channel filters that can be added to a call stack.
// TODO(ctiller): move this out so it can be used independently of
// the global registration mechanisms.
class StackSegment final {
public:
// Registration of one channel filter in the stack.
struct ChannelFilter {
size_t offset;
const ChannelFilterVtable* vtable;
};
StackSegment() = default;
explicit StackSegment(std::vector<ChannelFilter> filters,
uint8_t* channel_data);
StackSegment(const StackSegment& other) = delete;
StackSegment& operator=(const StackSegment& other) = delete;
StackSegment(StackSegment&& other) noexcept = default;
StackSegment& operator=(StackSegment&& other) = default;
// Add this segment to a call filter stack builder
void AddToCallFilterStack(CallFilters::StackBuilder& builder);
private:
// Combined channel data for the stack
class ChannelData : public RefCounted<ChannelData> {
public:
explicit ChannelData(std::vector<ChannelFilter> filters,
uint8_t* channel_data);
~ChannelData() override;
void AddToCallFilterStack(CallFilters::StackBuilder& builder);
private:
std::vector<ChannelFilter> filters_;
uint8_t* channel_data_;
};
RefCountedPtr<ChannelData> data_;
};
/// Construct a channel stack of some sort: see channel_stack.h for details
/// \a builder is the channel stack builder to build into.
GRPC_MUST_USE_RESULT
bool CreateStack(ChannelStackBuilder* builder) const;
// Create a segment of a channel stack.
// Terminators and post processors are not included in this construction:
// terminators are a legacy filter-stack concept, and post processors
// need to migrate to other mechanisms.
// TODO(ctiller): figure out other mechanisms.
absl::StatusOr<StackSegment> CreateStackSegment(
grpc_channel_stack_type type, const ChannelArgs& args) const;
private:
struct Filter {
Filter(const grpc_channel_filter* filter,
Filter(const grpc_channel_filter* filter, const ChannelFilterVtable* vtable,
std::vector<InclusionPredicate> predicates,
SourceLocation registration_source)
: filter(filter),
vtable(vtable),
predicates(std::move(predicates)),
registration_source(registration_source) {}
const grpc_channel_filter* filter;
const ChannelFilterVtable* vtable;
std::vector<InclusionPredicate> predicates;
SourceLocation registration_source;
bool CheckPredicates(const ChannelArgs& args) const;
@ -221,6 +291,18 @@ class ChannelInit {
std::vector<Filter> terminators;
std::vector<PostProcessor> post_processors;
};
template <typename T, typename = void>
struct VtableForType {
static const ChannelFilterVtable* vtable() { return nullptr; }
};
template <typename T>
struct VtableForType<T, absl::void_t<typename T::Call>> {
static const ChannelFilterVtable kVtable;
static const ChannelFilterVtable* vtable() { return &kVtable; }
};
StackConfig stack_configs_[GRPC_NUM_CHANNEL_STACK_TYPES];
static StackConfig BuildStackConfig(
@ -228,6 +310,22 @@ class ChannelInit {
PostProcessor* post_processors, grpc_channel_stack_type type);
};
template <typename T>
const ChannelInit::ChannelFilterVtable
ChannelInit::VtableForType<T, absl::void_t<typename T::Call>>::kVtable = {
sizeof(T), alignof(T),
[](void* data, const ChannelArgs& args) -> absl::Status {
// TODO(ctiller): fill in ChannelFilter::Args (2nd arg)
absl::StatusOr<T> r = T::Create(args, {});
if (!r.ok()) return r.status();
new (data) T(std::move(*r));
return absl::OkStatus();
},
[](void* data) { static_cast<T*>(data)->~T(); },
[](void* data, CallFilters::StackBuilder& builder) {
builder.Add(static_cast<T*>(data));
}};
} // namespace grpc_core
#endif // GRPC_SRC_CORE_LIB_SURFACE_CHANNEL_INIT_H

@ -221,9 +221,24 @@ void CallFilters::CancelDueToFailedPipeOperation() {
server_trailing_metadata_waiter_.Wake();
}
///////////////////////////////////////////////////////////////////////////////
// CallFilters::Stack
CallFilters::Stack::~Stack() {
for (auto& destructor : data_.channel_data_destructors) {
destructor.destroy(destructor.channel_data);
}
}
///////////////////////////////////////////////////////////////////////////////
// CallFilters::StackBuilder
CallFilters::StackBuilder::~StackBuilder() {
for (auto& destructor : data_.channel_data_destructors) {
destructor.destroy(destructor.channel_data);
}
}
RefCountedPtr<CallFilters::Stack> CallFilters::StackBuilder::Build() {
if (data_.call_data_size % data_.call_data_alignment != 0) {
data_.call_data_size += data_.call_data_alignment -

@ -344,6 +344,48 @@ struct AddOpImpl<
}
};
// $VALUE_HANDLE $INTERCEPTOR_NAME($VALUE_HANDLE, FilterType*)
template <typename FilterType, typename T,
T (FilterType::Call::*impl)(T, FilterType*)>
struct AddOpImpl<FilterType, T, T (FilterType::Call::*)(T, FilterType*), impl> {
static void Add(FilterType* channel_data, size_t call_offset,
Layout<FallibleOperator<T>>& to) {
to.Add(
0, 0,
FallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void* channel_data,
T value) -> Poll<ResultOr<T>> {
return ResultOr<T>{
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
std::move(value), static_cast<FilterType*>(channel_data)),
nullptr};
},
nullptr,
nullptr,
});
}
static void Add(FilterType* channel_data, size_t call_offset,
Layout<InfallibleOperator<T>>& to) {
to.Add(
0, 0,
InfallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void* channel_data, T value) -> Poll<T> {
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
*value, static_cast<FilterType*>(channel_data));
return (
static_cast<typename FilterType::Call*>(call_data)->*impl)(
std::move(value), static_cast<FilterType*>(channel_data));
},
nullptr,
nullptr,
});
}
};
// absl::Status $INTERCEPTOR_NAME($VALUE_TYPE&)
template <typename FilterType, typename T,
absl::Status (FilterType::Call::*impl)(typename T::element_type&)>
@ -369,6 +411,52 @@ struct AddOpImpl<FilterType, T,
nullptr,
});
}
static void Add(FilterType* channel_data, size_t call_offset,
Layout<InfallibleOperator<T>>& to) {
to.Add(
0, 0,
InfallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void*, T value) -> Poll<T> {
auto r =
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
*value);
if (r.ok()) return std::move(value);
return StatusCast<ServerMetadataHandle>(std::move(r));
},
nullptr,
nullptr,
});
}
};
// absl::Status $INTERCEPTOR_NAME(const $VALUE_TYPE&)
template <typename FilterType, typename T,
absl::Status (FilterType::Call::*impl)(
const typename T::element_type&)>
struct AddOpImpl<
FilterType, T,
absl::Status (FilterType::Call::*)(const typename T::element_type&), impl> {
static void Add(FilterType* channel_data, size_t call_offset,
Layout<FallibleOperator<T>>& to) {
to.Add(
0, 0,
FallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void*, T value) -> Poll<ResultOr<T>> {
auto r =
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
*value);
if (r.ok()) return ResultOr<T>{std::move(value), nullptr};
return ResultOr<T>{
nullptr, StatusCast<ServerMetadataHandle>(std::move(r))};
},
nullptr,
nullptr,
});
}
};
// absl::Status $INTERCEPTOR_NAME($VALUE_TYPE&, FilterType*)
@ -401,6 +489,64 @@ struct AddOpImpl<FilterType, T,
}
};
// absl::Status $INTERCEPTOR_NAME(const $VALUE_TYPE&, FilterType*)
template <typename FilterType, typename T,
absl::Status (FilterType::Call::*impl)(typename T::element_type&,
FilterType*)>
struct AddOpImpl<FilterType, T,
absl::Status (FilterType::Call::*)(
const typename T::element_type&, FilterType*),
impl> {
static void Add(FilterType* channel_data, size_t call_offset,
Layout<FallibleOperator<T>>& to) {
to.Add(
0, 0,
FallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void* channel_data,
T value) -> Poll<ResultOr<T>> {
auto r =
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
*value, static_cast<FilterType*>(channel_data));
if (IsStatusOk(r)) return ResultOr<T>{std::move(value), nullptr};
return ResultOr<T>{
nullptr, StatusCast<ServerMetadataHandle>(std::move(r))};
},
nullptr,
nullptr,
});
}
};
// absl::StatusOr<$VALUE_HANDLE> $INTERCEPTOR_NAME($VALUE_HANDLE, FilterType*)
template <typename FilterType, typename T,
absl::StatusOr<T> (FilterType::Call::*impl)(T, FilterType*)>
struct AddOpImpl<FilterType, T,
absl::StatusOr<T> (FilterType::Call::*)(T, FilterType*),
impl> {
static void Add(FilterType* channel_data, size_t call_offset,
Layout<FallibleOperator<T>>& to) {
to.Add(
0, 0,
FallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void* channel_data,
T value) -> Poll<ResultOr<T>> {
auto r =
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
std::move(value), static_cast<FilterType*>(channel_data));
if (IsStatusOk(r)) return ResultOr<T>{std::move(*r), nullptr};
return ResultOr<T>{
nullptr, StatusCast<ServerMetadataHandle>(std::move(r))};
},
nullptr,
nullptr,
});
}
};
// ServerMetadataHandle $INTERCEPTOR_NAME($VALUE_TYPE&)
template <typename FilterType, typename T,
ServerMetadataHandle (FilterType::Call::*impl)(
@ -430,6 +576,35 @@ struct AddOpImpl<FilterType, T,
}
};
// ServerMetadataHandle $INTERCEPTOR_NAME(const $VALUE_TYPE&)
template <typename FilterType, typename T,
ServerMetadataHandle (FilterType::Call::*impl)(
const typename T::element_type&)>
struct AddOpImpl<FilterType, T,
ServerMetadataHandle (FilterType::Call::*)(
const typename T::element_type&),
impl> {
static void Add(FilterType* channel_data, size_t call_offset,
Layout<FallibleOperator<T>>& to) {
to.Add(
0, 0,
FallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void*, T value) -> Poll<ResultOr<T>> {
auto r =
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
*value);
if (r == nullptr) return ResultOr<T>{std::move(value), nullptr};
return ResultOr<T>{
nullptr, StatusCast<ServerMetadataHandle>(std::move(r))};
},
nullptr,
nullptr,
});
}
};
// ServerMetadataHandle $INTERCEPTOR_NAME($VALUE_TYPE&, FilterType*)
template <typename FilterType, typename T,
ServerMetadataHandle (FilterType::Call::*impl)(
@ -460,6 +635,36 @@ struct AddOpImpl<FilterType, T,
}
};
// ServerMetadataHandle $INTERCEPTOR_NAME(const $VALUE_TYPE&, FilterType*)
template <typename FilterType, typename T,
ServerMetadataHandle (FilterType::Call::*impl)(
const typename T::element_type&, FilterType*)>
struct AddOpImpl<FilterType, T,
ServerMetadataHandle (FilterType::Call::*)(
const typename T::element_type&, FilterType*),
impl> {
static void Add(FilterType* channel_data, size_t call_offset,
Layout<FallibleOperator<T>>& to) {
to.Add(
0, 0,
FallibleOperator<T>{
channel_data,
call_offset,
[](void*, void* call_data, void* channel_data,
T value) -> Poll<ResultOr<T>> {
auto r =
(static_cast<typename FilterType::Call*>(call_data)->*impl)(
*value, static_cast<FilterType*>(channel_data));
if (r == nullptr) return ResultOr<T>{std::move(value), nullptr};
return ResultOr<T>{
nullptr, StatusCast<ServerMetadataHandle>(std::move(r))};
},
nullptr,
nullptr,
});
}
};
// PROMISE_RETURNING(absl::Status) $INTERCEPTOR_NAME($VALUE_TYPE&)
template <typename FilterType, typename T, typename R,
R (FilterType::Call::*impl)(typename T::element_type&)>
@ -565,6 +770,11 @@ struct AddOpImpl<
}
};
struct ChannelDataDestructor {
void (*destroy)(void* channel_data);
void* channel_data;
};
// StackData contains the main datastructures built up by this module.
// It's a complete representation of all the code that needs to be invoked
// to execute a call for a given set of filters.
@ -590,6 +800,9 @@ struct StackData {
// We use a bespoke data structure here because finalizers can never be
// asynchronous.
std::vector<Finalizer> finalizers;
// A list of functions to call when this stack data is destroyed
// (to capture ownership of channel data)
std::vector<ChannelDataDestructor> channel_data_destructors;
// Add one filter to the list of filters, and update alignment.
// Returns the offset of the call data for this filter.
@ -721,7 +934,7 @@ struct StackData {
template <typename FilterType>
void AddFinalizer(FilterType*, size_t, const NoInterceptor* p) {
GPR_DEBUG_ASSERT(p == &FilterType::OnFinalize);
GPR_DEBUG_ASSERT(p == &FilterType::Call::OnFinalize);
}
template <typename FilterType>
@ -938,6 +1151,9 @@ class CallFilters {
// It contains pointers to the individual filters, yet it does not own those
// pointers: it's expected that some other object will track that ownership.
class Stack : public RefCounted<Stack> {
public:
~Stack() override;
private:
friend class CallFilters;
friend class StackBuilder;
@ -949,6 +1165,8 @@ class CallFilters {
// the stack, then call Build() to generate a ref counted Stack object.
class StackBuilder {
public:
~StackBuilder();
template <typename FilterType>
void Add(FilterType* filter) {
const size_t call_offset = data_.AddFilter<FilterType>(filter);
@ -960,6 +1178,15 @@ class CallFilters {
data_.AddFinalizer(filter, call_offset, &FilterType::Call::OnFinalize);
}
void AddOwnedObject(void (*destroy)(void* p), void* p) {
data_.channel_data_destructors.push_back({destroy, p});
}
template <typename T>
void AddOwnedObject(RefCountedPtr<T> p) {
AddOwnedObject([](void* p) { static_cast<T*>(p)->Unref(); }, p.release());
}
RefCountedPtr<Stack> Build();
private:

@ -201,6 +201,64 @@ TEST(ChannelInitTest, CanPostProcessFilters) {
std::vector<std::string>({"foo", "aaa", "bar"}));
}
class TestFilter1 {
public:
explicit TestFilter1(int* p) : p_(p) {}
static absl::StatusOr<TestFilter1> Create(const ChannelArgs& args, Empty) {
EXPECT_EQ(args.GetInt("foo"), 1);
return TestFilter1(args.GetPointer<int>("p"));
}
static const grpc_channel_filter kFilter;
class Call {
public:
explicit Call(TestFilter1* filter) {
EXPECT_EQ(*filter->x_, 0);
*filter->x_ = 1;
++*filter->p_;
}
static const NoInterceptor OnClientInitialMetadata;
static const NoInterceptor OnServerInitialMetadata;
static const NoInterceptor OnServerTrailingMetadata;
static const NoInterceptor OnClientToServerMessage;
static const NoInterceptor OnServerToClientMessage;
static const NoInterceptor OnFinalize;
};
private:
std::unique_ptr<int> x_ = std::make_unique<int>(0);
int* const p_;
};
const grpc_channel_filter TestFilter1::kFilter = {
nullptr, nullptr, nullptr, nullptr, 0, nullptr, nullptr,
nullptr, 0, nullptr, nullptr, nullptr, nullptr, "test_filter1"};
const NoInterceptor TestFilter1::Call::OnClientInitialMetadata;
const NoInterceptor TestFilter1::Call::OnServerInitialMetadata;
const NoInterceptor TestFilter1::Call::OnServerTrailingMetadata;
const NoInterceptor TestFilter1::Call::OnClientToServerMessage;
const NoInterceptor TestFilter1::Call::OnServerToClientMessage;
const NoInterceptor TestFilter1::Call::OnFinalize;
TEST(ChannelInitTest, CanCreateFilterWithCall) {
ChannelInit::Builder b;
b.RegisterFilter<TestFilter1>(GRPC_CLIENT_CHANNEL);
auto init = b.Build();
int p = 0;
auto segment = init.CreateStackSegment(
GRPC_CLIENT_CHANNEL,
ChannelArgs().Set("foo", 1).Set("p", ChannelArgs::UnownedPointer(&p)));
ASSERT_TRUE(segment.ok()) << segment.status();
CallFilters::StackBuilder stack_builder;
segment->AddToCallFilterStack(stack_builder);
segment = absl::CancelledError(); // force the segment to be destroyed
auto stack = stack_builder.Build();
{ CallFilters call_filters(stack); }
EXPECT_EQ(p, 1);
}
} // namespace
} // namespace grpc_core

Loading…
Cancel
Save