[call v3] add dynamic filter support to client channel (#36877)

Also made some minor improvements to the `ConfigSelector` API.

Closes #36877

COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36877 from markdroth:client_channel_v3_dynamic_filters 6a539fe320
PiperOrigin-RevId: 642755276
pull/36921/head
Mark D. Roth 6 months ago committed by Copybara-Service
parent 8564f72e8e
commit f7ce3ee9d5
  1. 2
      CMakeLists.txt
  2. 1
      Makefile
  3. 1
      Package.swift
  4. 2
      build_autogenerated.yaml
  5. 1
      config.m4
  6. 1
      config.w32
  7. 1
      gRPC-Core.podspec
  8. 1
      grpc.gemspec
  9. 1
      package.xml
  10. 6
      src/core/BUILD
  11. 7
      src/core/client_channel/client_channel.cc
  12. 60
      src/core/client_channel/config_selector.cc
  13. 31
      src/core/client_channel/config_selector.h
  14. 40
      src/core/resolver/xds/xds_resolver.cc
  15. 4
      src/core/xds/grpc/xds_http_fault_filter.cc
  16. 1
      src/core/xds/grpc/xds_http_fault_filter.h
  17. 4
      src/core/xds/grpc/xds_http_filters.h
  18. 4
      src/core/xds/grpc/xds_http_rbac_filter.cc
  19. 1
      src/core/xds/grpc/xds_http_rbac_filter.h
  20. 5
      src/core/xds/grpc/xds_http_stateful_session_filter.cc
  21. 1
      src/core/xds/grpc/xds_http_stateful_session_filter.h
  22. 1
      src/python/grpcio/grpc_core_dependencies.py
  23. 102
      test/core/client_channel/client_channel_test.cc
  24. 5
      test/cpp/end2end/client_lb_end2end_test.cc
  25. 1
      tools/doxygen/Doxyfile.c++.internal
  26. 1
      tools/doxygen/Doxyfile.core.internal

2
CMakeLists.txt generated

@ -1853,7 +1853,6 @@ add_library(grpc
src/core/client_channel/client_channel_filter.cc
src/core/client_channel/client_channel_plugin.cc
src/core/client_channel/client_channel_service_config.cc
src/core/client_channel/config_selector.cc
src/core/client_channel/dynamic_filters.cc
src/core/client_channel/global_subchannel_pool.cc
src/core/client_channel/load_balanced_call_destination.cc
@ -2946,7 +2945,6 @@ add_library(grpc_unsecure
src/core/client_channel/client_channel_filter.cc
src/core/client_channel/client_channel_plugin.cc
src/core/client_channel/client_channel_service_config.cc
src/core/client_channel/config_selector.cc
src/core/client_channel/dynamic_filters.cc
src/core/client_channel/global_subchannel_pool.cc
src/core/client_channel/load_balanced_call_destination.cc

1
Makefile generated

@ -675,7 +675,6 @@ LIBGRPC_SRC = \
src/core/client_channel/client_channel_filter.cc \
src/core/client_channel/client_channel_plugin.cc \
src/core/client_channel/client_channel_service_config.cc \
src/core/client_channel/config_selector.cc \
src/core/client_channel/dynamic_filters.cc \
src/core/client_channel/global_subchannel_pool.cc \
src/core/client_channel/load_balanced_call_destination.cc \

1
Package.swift generated

@ -136,7 +136,6 @@ let package = Package(
"src/core/client_channel/client_channel_plugin.cc",
"src/core/client_channel/client_channel_service_config.cc",
"src/core/client_channel/client_channel_service_config.h",
"src/core/client_channel/config_selector.cc",
"src/core/client_channel/config_selector.h",
"src/core/client_channel/connector.h",
"src/core/client_channel/dynamic_filters.cc",

@ -1258,7 +1258,6 @@ libs:
- src/core/client_channel/client_channel_filter.cc
- src/core/client_channel/client_channel_plugin.cc
- src/core/client_channel/client_channel_service_config.cc
- src/core/client_channel/config_selector.cc
- src/core/client_channel/dynamic_filters.cc
- src/core/client_channel/global_subchannel_pool.cc
- src/core/client_channel/load_balanced_call_destination.cc
@ -2714,7 +2713,6 @@ libs:
- src/core/client_channel/client_channel_filter.cc
- src/core/client_channel/client_channel_plugin.cc
- src/core/client_channel/client_channel_service_config.cc
- src/core/client_channel/config_selector.cc
- src/core/client_channel/dynamic_filters.cc
- src/core/client_channel/global_subchannel_pool.cc
- src/core/client_channel/load_balanced_call_destination.cc

1
config.m4 generated

@ -50,7 +50,6 @@ if test "$PHP_GRPC" != "no"; then
src/core/client_channel/client_channel_filter.cc \
src/core/client_channel/client_channel_plugin.cc \
src/core/client_channel/client_channel_service_config.cc \
src/core/client_channel/config_selector.cc \
src/core/client_channel/dynamic_filters.cc \
src/core/client_channel/global_subchannel_pool.cc \
src/core/client_channel/load_balanced_call_destination.cc \

1
config.w32 generated

@ -15,7 +15,6 @@ if (PHP_GRPC != "no") {
"src\\core\\client_channel\\client_channel_filter.cc " +
"src\\core\\client_channel\\client_channel_plugin.cc " +
"src\\core\\client_channel\\client_channel_service_config.cc " +
"src\\core\\client_channel\\config_selector.cc " +
"src\\core\\client_channel\\dynamic_filters.cc " +
"src\\core\\client_channel\\global_subchannel_pool.cc " +
"src\\core\\client_channel\\load_balanced_call_destination.cc " +

1
gRPC-Core.podspec generated

@ -255,7 +255,6 @@ Pod::Spec.new do |s|
'src/core/client_channel/client_channel_plugin.cc',
'src/core/client_channel/client_channel_service_config.cc',
'src/core/client_channel/client_channel_service_config.h',
'src/core/client_channel/config_selector.cc',
'src/core/client_channel/config_selector.h',
'src/core/client_channel/connector.h',
'src/core/client_channel/dynamic_filters.cc',

1
grpc.gemspec generated

@ -142,7 +142,6 @@ Gem::Specification.new do |s|
s.files += %w( src/core/client_channel/client_channel_plugin.cc )
s.files += %w( src/core/client_channel/client_channel_service_config.cc )
s.files += %w( src/core/client_channel/client_channel_service_config.h )
s.files += %w( src/core/client_channel/config_selector.cc )
s.files += %w( src/core/client_channel/config_selector.h )
s.files += %w( src/core/client_channel/connector.h )
s.files += %w( src/core/client_channel/dynamic_filters.cc )

1
package.xml generated

@ -124,7 +124,6 @@
<file baseinstalldir="/" name="src/core/client_channel/client_channel_plugin.cc" role="src" />
<file baseinstalldir="/" name="src/core/client_channel/client_channel_service_config.cc" role="src" />
<file baseinstalldir="/" name="src/core/client_channel/client_channel_service_config.h" role="src" />
<file baseinstalldir="/" name="src/core/client_channel/config_selector.cc" role="src" />
<file baseinstalldir="/" name="src/core/client_channel/config_selector.h" role="src" />
<file baseinstalldir="/" name="src/core/client_channel/connector.h" role="src" />
<file baseinstalldir="/" name="src/core/client_channel/dynamic_filters.cc" role="src" />

@ -3295,9 +3295,6 @@ grpc_cc_library(
grpc_cc_library(
name = "config_selector",
srcs = [
"client_channel/config_selector.cc",
],
hdrs = [
"client_channel/config_selector.h",
],
@ -3313,9 +3310,11 @@ grpc_cc_library(
"channel_fwd",
"client_channel_internal_header",
"grpc_service_config",
"interception_chain",
"metadata_batch",
"ref_counted",
"slice",
"unique_type_name",
"useful",
"//:gpr_public_hdrs",
"//:grpc_public_hdrs",
@ -5215,6 +5214,7 @@ grpc_cc_library(
"grpc_tls_credentials",
"grpc_transport_chttp2_client_connector",
"init_internally",
"interception_chain",
"iomgr_fwd",
"json",
"json_args",

@ -1195,14 +1195,17 @@ void ClientChannel::UpdateServiceConfigInDataPlaneLocked() {
}
CoreConfiguration::Get().channel_init().AddToInterceptionChainBuilder(
GRPC_CLIENT_CHANNEL, builder);
// TODO(roth): add filters returned by config selector
// Create call destination.
// Add filters returned by the config selector (e.g., xDS HTTP filters).
config_selector->AddFilters(builder);
// TODO(roth, ctiller): When we implement the retry interceptor, that
// needs to be added *after* the filters added by the config selector.
const bool enable_retries =
!channel_args_.WantMinimalStack() &&
channel_args_.GetBool(GRPC_ARG_ENABLE_RETRIES).value_or(true);
if (enable_retries) {
Crash("call v3 stack does not yet support retries");
}
// Create call destination.
auto top_of_stack_call_destination = builder.Build(call_destination_);
// Send result to data plane.
if (!top_of_stack_call_destination.ok()) {

@ -1,60 +0,0 @@
//
// Copyright 2020 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/client_channel/config_selector.h"
#include "src/core/lib/channel/channel_args.h"
#include "src/core/util/useful.h"
namespace grpc_core {
namespace {
void* ConfigSelectorArgCopy(void* p) {
ConfigSelector* config_selector = static_cast<ConfigSelector*>(p);
config_selector->Ref().release();
return p;
}
void ConfigSelectorArgDestroy(void* p) {
ConfigSelector* config_selector = static_cast<ConfigSelector*>(p);
config_selector->Unref();
}
int ConfigSelectorArgCmp(void* p, void* q) { return QsortCompare(p, q); }
const grpc_arg_pointer_vtable kChannelArgVtable = {
ConfigSelectorArgCopy, ConfigSelectorArgDestroy, ConfigSelectorArgCmp};
} // namespace
grpc_arg ConfigSelector::MakeChannelArg() const {
return grpc_channel_arg_pointer_create(
const_cast<char*>(GRPC_ARG_CONFIG_SELECTOR),
const_cast<ConfigSelector*>(this), &kChannelArgVtable);
}
RefCountedPtr<ConfigSelector> ConfigSelector::GetFromChannelArgs(
const grpc_channel_args& args) {
ConfigSelector* config_selector =
grpc_channel_args_find_pointer<ConfigSelector>(&args,
GRPC_ARG_CONFIG_SELECTOR);
return config_selector != nullptr ? config_selector->Ref() : nullptr;
}
} // namespace grpc_core

@ -35,8 +35,10 @@
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h"
#include "src/core/lib/gprpp/unique_type_name.h"
#include "src/core/lib/resource_quota/arena.h"
#include "src/core/lib/slice/slice.h"
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/lib/transport/metadata_batch.h"
#include "src/core/service_config/service_config.h"
#include "src/core/util/useful.h"
@ -50,34 +52,32 @@ namespace grpc_core {
// MethodConfig and provide input to LB policies on a per-call basis.
class ConfigSelector : public RefCounted<ConfigSelector> {
public:
struct GetCallConfigArgs {
grpc_metadata_batch* initial_metadata;
Arena* arena;
ClientChannelServiceConfigCallData* service_config_call_data;
};
~ConfigSelector() override = default;
virtual const char* name() const = 0;
virtual UniqueTypeName name() const = 0;
static bool Equals(const ConfigSelector* cs1, const ConfigSelector* cs2) {
if (cs1 == nullptr) return cs2 == nullptr;
if (cs2 == nullptr) return false;
if (strcmp(cs1->name(), cs2->name()) != 0) return false;
if (cs1->name() != cs2->name()) return false;
return cs1->Equals(cs2);
}
// The channel will call this when the resolver returns a new ConfigSelector
// to determine what set of dynamic filters will be configured.
virtual void AddFilters(InterceptionChainBuilder& /*builder*/) {}
// TODO(roth): Remove this once the legacy filter stack goes away.
virtual std::vector<const grpc_channel_filter*> GetFilters() { return {}; }
// Returns the call config to use for the call, or a status to fail
// the call with.
// Gets the configuration for the call and stores it in service config
// call data.
struct GetCallConfigArgs {
grpc_metadata_batch* initial_metadata;
Arena* arena;
ClientChannelServiceConfigCallData* service_config_call_data;
};
virtual absl::Status GetCallConfig(GetCallConfigArgs args) = 0;
grpc_arg MakeChannelArg() const;
static RefCountedPtr<ConfigSelector> GetFromChannelArgs(
const grpc_channel_args& args);
static absl::string_view ChannelArgName() { return GRPC_ARG_CONFIG_SELECTOR; }
static int ChannelArgsCompare(const ConfigSelector* a,
const ConfigSelector* b) {
@ -101,7 +101,10 @@ class DefaultConfigSelector final : public ConfigSelector {
DCHECK(service_config_ != nullptr);
}
const char* name() const override { return "default"; }
UniqueTypeName name() const override {
static UniqueTypeName::Factory kFactory("default");
return kFactory.Create();
}
absl::Status GetCallConfig(GetCallConfigArgs args) override {
Slice* path = args.initial_metadata->get_pointer(HttpPathMetadata());

@ -270,7 +270,10 @@ class XdsResolver final : public Resolver {
RefCountedPtr<RouteConfigData> route_config_data);
~XdsConfigSelector() override;
const char* name() const override { return "XdsConfigSelector"; }
UniqueTypeName name() const override {
static UniqueTypeName::Factory kFactory("XdsConfigSelector");
return kFactory.Create();
}
bool Equals(const ConfigSelector* other) const override {
const auto* other_xds = static_cast<const XdsConfigSelector*>(other);
@ -281,14 +284,14 @@ class XdsResolver final : public Resolver {
absl::Status GetCallConfig(GetCallConfigArgs args) override;
std::vector<const grpc_channel_filter*> GetFilters() override {
return filters_;
}
void AddFilters(InterceptionChainBuilder& builder) override;
std::vector<const grpc_channel_filter*> GetFilters() override;
private:
RefCountedPtr<XdsResolver> resolver_;
RefCountedPtr<RouteConfigData> route_config_data_;
std::vector<const grpc_channel_filter*> filters_;
std::vector<const XdsHttpFilterImpl*> filters_;
};
class XdsRouteStateAttributeImpl final : public XdsRouteStateAttribute {
@ -641,12 +644,9 @@ XdsResolver::XdsConfigSelector::XdsConfigSelector(
http_filter_registry.GetFilterForType(
http_filter.config.config_proto_type_name);
CHECK_NE(filter_impl, nullptr);
// Add C-core filter to list.
if (filter_impl->channel_filter() != nullptr) {
filters_.push_back(filter_impl->channel_filter());
// Add filter to list.
filters_.push_back(filter_impl);
}
}
filters_.push_back(&ClusterSelectionFilter::kFilter);
}
XdsResolver::XdsConfigSelector::~XdsConfigSelector() {
@ -799,6 +799,26 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig(
return absl::OkStatus();
}
void XdsResolver::XdsConfigSelector::AddFilters(
InterceptionChainBuilder& builder) {
for (const XdsHttpFilterImpl* filter : filters_) {
filter->AddFilter(builder);
}
builder.Add<ClusterSelectionFilter>();
}
std::vector<const grpc_channel_filter*>
XdsResolver::XdsConfigSelector::GetFilters() {
std::vector<const grpc_channel_filter*> filters;
for (const XdsHttpFilterImpl* filter : filters_) {
if (filter->channel_filter() != nullptr) {
filters.push_back(filter->channel_filter());
}
}
filters.push_back(&ClusterSelectionFilter::kFilter);
return filters;
}
//
// XdsResolver::XdsRouteStateAttributeImpl
//

@ -214,6 +214,10 @@ XdsHttpFaultFilter::GenerateFilterConfigOverride(
return GenerateFilterConfig(context, std::move(extension), errors);
}
void XdsHttpFaultFilter::AddFilter(InterceptionChainBuilder& builder) const {
builder.Add<FaultInjectionFilter>();
}
const grpc_channel_filter* XdsHttpFaultFilter::channel_filter() const {
return &FaultInjectionFilter::kFilter;
}

@ -44,6 +44,7 @@ class XdsHttpFaultFilter final : public XdsHttpFilterImpl {
absl::optional<FilterConfig> GenerateFilterConfigOverride(
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& builder) const override;
const grpc_channel_filter* channel_filter() const override;
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(

@ -35,6 +35,7 @@
#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/channel/channel_fwd.h"
#include "src/core/lib/gprpp/validation_errors.h"
#include "src/core/lib/transport/interception_chain.h"
#include "src/core/util/json/json.h"
#include "src/core/util/json/json_writer.h"
#include "src/core/xds/grpc/xds_common_types.h"
@ -96,6 +97,8 @@ class XdsHttpFilterImpl {
ValidationErrors* errors) const = 0;
// C-core channel filter implementation.
virtual void AddFilter(InterceptionChainBuilder& builder) const = 0;
// TODO(roth): Remove this once the legacy filter stack goes away.
virtual const grpc_channel_filter* channel_filter() const = 0;
// Modifies channel args that may affect service config parsing (not
@ -135,6 +138,7 @@ class XdsHttpRouterFilter final : public XdsHttpFilterImpl {
absl::optional<FilterConfig> GenerateFilterConfigOverride(
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& /*builder*/) const override {}
const grpc_channel_filter* channel_filter() const override { return nullptr; }
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(
const FilterConfig& /*hcm_filter_config*/,

@ -564,6 +564,10 @@ XdsHttpRbacFilter::GenerateFilterConfigOverride(
return FilterConfig{OverrideConfigProtoName(), std::move(rbac_json)};
}
void XdsHttpRbacFilter::AddFilter(InterceptionChainBuilder& builder) const {
builder.Add<RbacFilter>();
}
const grpc_channel_filter* XdsHttpRbacFilter::channel_filter() const {
return &RbacFilter::kFilterVtable;
}

@ -44,6 +44,7 @@ class XdsHttpRbacFilter final : public XdsHttpFilterImpl {
absl::optional<FilterConfig> GenerateFilterConfigOverride(
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& builder) const override;
const grpc_channel_filter* channel_filter() const override;
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(

@ -194,6 +194,11 @@ XdsHttpStatefulSessionFilter::GenerateFilterConfigOverride(
Json::FromObject(std::move(config))};
}
void XdsHttpStatefulSessionFilter::AddFilter(
InterceptionChainBuilder& builder) const {
builder.Add<StatefulSessionFilter>();
}
const grpc_channel_filter* XdsHttpStatefulSessionFilter::channel_filter()
const {
return &StatefulSessionFilter::kFilter;

@ -44,6 +44,7 @@ class XdsHttpStatefulSessionFilter final : public XdsHttpFilterImpl {
absl::optional<FilterConfig> GenerateFilterConfigOverride(
const XdsResourceType::DecodeContext& context, XdsExtension extension,
ValidationErrors* errors) const override;
void AddFilter(InterceptionChainBuilder& builder) const override;
const grpc_channel_filter* channel_filter() const override;
ChannelArgs ModifyChannelArgs(const ChannelArgs& args) const override;
absl::StatusOr<ServiceConfigJsonEntry> GenerateServiceConfig(

@ -24,7 +24,6 @@ CORE_SOURCE_FILES = [
'src/core/client_channel/client_channel_filter.cc',
'src/core/client_channel/client_channel_plugin.cc',
'src/core/client_channel/client_channel_service_config.cc',
'src/core/client_channel/config_selector.cc',
'src/core/client_channel/dynamic_filters.cc',
'src/core/client_channel/global_subchannel_pool.cc',
'src/core/client_channel/load_balanced_call_destination.cc',

@ -23,7 +23,9 @@
#include <grpc/grpc.h>
#include "src/core/lib/address_utils/parse_address.h"
#include "src/core/lib/channel/promise_based_filter.h"
#include "src/core/lib/config/core_configuration.h"
#include "src/core/service_config/service_config_impl.h"
#include "test/core/call/yodel/yodel_test.h"
namespace grpc_core {
@ -77,11 +79,21 @@ class ClientChannelTest : public YodelTest {
}
Resolver::Result MakeSuccessfulResolutionResult(
absl::string_view endpoint_address) {
absl::string_view endpoint_address,
absl::StatusOr<RefCountedPtr<ServiceConfig>> service_config = nullptr,
RefCountedPtr<ConfigSelector> config_selector = nullptr) {
Resolver::Result result;
grpc_resolved_address address;
CHECK(grpc_parse_uri(URI::Parse(endpoint_address).value(), &address));
result.addresses = EndpointAddressesList({EndpointAddresses{address, {}}});
result.service_config = std::move(service_config);
if (config_selector != nullptr) {
CHECK(result.service_config.ok())
<< "channel does not use ConfigSelector without service config";
CHECK(*result.service_config != nullptr)
<< "channel does not use ConfigSelector without service config";
result.args = ChannelArgs().SetObject(std::move(config_selector));
}
return result;
}
@ -268,6 +280,94 @@ CLIENT_CHANNEL_TEST(StartCall) {
WaitForAllPendingWork();
}
// A filter that adds metadata foo=bar.
class TestFilter : public ImplementChannelFilter<TestFilter> {
public:
class Call {
public:
void OnClientInitialMetadata(ClientMetadata& md) {
md.Append("foo", Slice::FromStaticString("bar"),
[](absl::string_view error, const Slice&) {
FAIL() << "error encoding metadata: " << error;
});
}
static const NoInterceptor OnClientToServerMessage;
static const NoInterceptor OnClientToServerHalfClose;
static const NoInterceptor OnServerInitialMetadata;
static const NoInterceptor OnServerToClientMessage;
static const NoInterceptor OnServerTrailingMetadata;
static const NoInterceptor OnFinalize;
};
static absl::StatusOr<std::unique_ptr<TestFilter>> Create(
const ChannelArgs& /*args*/, ChannelFilter::Args /*filter_args*/) {
return std::make_unique<TestFilter>();
}
};
const NoInterceptor TestFilter::Call::OnClientToServerMessage;
const NoInterceptor TestFilter::Call::OnClientToServerHalfClose;
const NoInterceptor TestFilter::Call::OnServerInitialMetadata;
const NoInterceptor TestFilter::Call::OnServerToClientMessage;
const NoInterceptor TestFilter::Call::OnServerTrailingMetadata;
const NoInterceptor TestFilter::Call::OnFinalize;
// A config selector that adds TestFilter as a dynamic filter.
class TestConfigSelector : public ConfigSelector {
public:
UniqueTypeName name() const override {
static UniqueTypeName::Factory kFactory("test");
return kFactory.Create();
}
void AddFilters(InterceptionChainBuilder& builder) override {
builder.Add<TestFilter>();
}
absl::Status GetCallConfig(GetCallConfigArgs /*args*/) override {
return absl::OkStatus();
}
// Any instance of this class will behave the same, so all comparisons
// are true.
bool Equals(const ConfigSelector* /*other*/) const override { return true; }
};
CLIENT_CHANNEL_TEST(ConfigSelectorWithDynamicFilters) {
auto& channel = InitChannel(ChannelArgs());
auto call = MakeCallPair(MakeClientInitialMetadata(), channel.event_engine(),
channel.call_arena_allocator()->MakeArena());
channel.StartCall(std::move(call.handler));
auto service_config = ServiceConfigImpl::Create(ChannelArgs(), "{}");
ASSERT_TRUE(service_config.ok());
QueueNameResolutionResult(MakeSuccessfulResolutionResult(
"ipv4:127.0.0.1:1234", std::move(service_config),
MakeRefCounted<TestConfigSelector>()));
auto call_handler = TickUntilCallStarted();
SpawnTestSeq(
call_handler, "check_initial_metadata",
[call_handler]() mutable {
return call_handler.PullClientInitialMetadata();
},
[](ValueOrFailure<ClientMetadataHandle> md) {
EXPECT_TRUE(md.ok());
if (md.ok()) {
std::string buffer;
auto value = (*md)->GetStringValue("foo", &buffer);
EXPECT_TRUE(value.has_value());
if (value.has_value()) EXPECT_EQ(*value, "bar");
}
return Empty{};
});
SpawnTestSeq(call.initiator, "cancel",
[call_initiator = call.initiator]() mutable {
call_initiator.Cancel();
return Empty{};
});
WaitForAllPendingWork();
}
// TODO(ctiller, roth): MANY more test cases
// - Resolver returns an error for the initial result, then returns a valid
// result.

@ -2947,7 +2947,10 @@ TEST_F(ControlPlaneStatusRewritingTest, RewritesFromConfigSelector) {
public:
explicit FailConfigSelector(absl::Status status)
: status_(std::move(status)) {}
const char* name() const override { return "FailConfigSelector"; }
grpc_core::UniqueTypeName name() const override {
static grpc_core::UniqueTypeName::Factory kFactory("FailConfigSelector");
return kFactory.Create();
}
bool Equals(const ConfigSelector* other) const override {
return status_ == static_cast<const FailConfigSelector*>(other)->status_;
}

@ -1104,7 +1104,6 @@ src/core/client_channel/client_channel_internal.h \
src/core/client_channel/client_channel_plugin.cc \
src/core/client_channel/client_channel_service_config.cc \
src/core/client_channel/client_channel_service_config.h \
src/core/client_channel/config_selector.cc \
src/core/client_channel/config_selector.h \
src/core/client_channel/connector.h \
src/core/client_channel/dynamic_filters.cc \

@ -907,7 +907,6 @@ src/core/client_channel/client_channel_internal.h \
src/core/client_channel/client_channel_plugin.cc \
src/core/client_channel/client_channel_service_config.cc \
src/core/client_channel/client_channel_service_config.h \
src/core/client_channel/config_selector.cc \
src/core/client_channel/config_selector.h \
src/core/client_channel/connector.h \
src/core/client_channel/dynamic_filters.cc \

Loading…
Cancel
Save