ServerConfigSelector, provider and filter (#27717)
* ServerConfigSelector, provider and filter * Reviewer comments * Reviewer comments * Add some tests * Fix include guards * Regenerate projects and fix sanity check * Reviewer commentspull/27746/head
parent
fbf9801b83
commit
e2b044d6d8
11 changed files with 658 additions and 0 deletions
@ -0,0 +1,67 @@ |
|||||||
|
//
|
||||||
|
// 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/server_config_selector/server_config_selector.h" |
||||||
|
|
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace { |
||||||
|
|
||||||
|
void* ServerConfigSelectorProviderArgCopy(void* p) { |
||||||
|
ServerConfigSelectorProvider* arg = |
||||||
|
static_cast<ServerConfigSelectorProvider*>(p); |
||||||
|
return arg->Ref().release(); |
||||||
|
} |
||||||
|
|
||||||
|
void ServerConfigSelectorProviderArgDestroy(void* p) { |
||||||
|
ServerConfigSelectorProvider* arg = |
||||||
|
static_cast<ServerConfigSelectorProvider*>(p); |
||||||
|
arg->Unref(); |
||||||
|
} |
||||||
|
|
||||||
|
int ServerConfigSelectorProviderArgCmp(void* p, void* q) { |
||||||
|
return QsortCompare(p, q); |
||||||
|
} |
||||||
|
|
||||||
|
const grpc_arg_pointer_vtable kChannelArgVtable = { |
||||||
|
ServerConfigSelectorProviderArgCopy, ServerConfigSelectorProviderArgDestroy, |
||||||
|
ServerConfigSelectorProviderArgCmp}; |
||||||
|
|
||||||
|
const char* kServerConfigSelectorProviderChannelArgName = |
||||||
|
"grpc.internal.server_config_selector_provider"; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
grpc_arg ServerConfigSelectorProvider::MakeChannelArg() const { |
||||||
|
return grpc_channel_arg_pointer_create( |
||||||
|
const_cast<char*>(kServerConfigSelectorProviderChannelArgName), |
||||||
|
const_cast<ServerConfigSelectorProvider*>(this), &kChannelArgVtable); |
||||||
|
} |
||||||
|
|
||||||
|
RefCountedPtr<ServerConfigSelectorProvider> |
||||||
|
ServerConfigSelectorProvider::GetFromChannelArgs( |
||||||
|
const grpc_channel_args& args) { |
||||||
|
ServerConfigSelectorProvider* config_selector_provider = |
||||||
|
grpc_channel_args_find_pointer<ServerConfigSelectorProvider>( |
||||||
|
&args, kServerConfigSelectorProviderChannelArgName); |
||||||
|
return config_selector_provider != nullptr ? config_selector_provider->Ref() |
||||||
|
: nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,70 @@ |
|||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_FILTERS_SERVER_CONFIG_SELECTOR_SERVER_CONFIG_SELECTOR_H |
||||||
|
#define GRPC_CORE_EXT_FILTERS_SERVER_CONFIG_SELECTOR_SERVER_CONFIG_SELECTOR_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "absl/status/statusor.h" |
||||||
|
|
||||||
|
#include "src/core/ext/service_config/service_config.h" |
||||||
|
#include "src/core/lib/transport/metadata_batch.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
// ServerConfigSelector allows for choosing the service config to apply to a
|
||||||
|
// server-side call based on the received initial metadata.
|
||||||
|
class ServerConfigSelector : public RefCounted<ServerConfigSelector> { |
||||||
|
public: |
||||||
|
// Configuration to apply to an incoming call
|
||||||
|
struct CallConfig { |
||||||
|
grpc_error_handle error = GRPC_ERROR_NONE; |
||||||
|
const ServiceConfigParser::ParsedConfigVector* method_configs = nullptr; |
||||||
|
RefCountedPtr<ServiceConfig> service_config; |
||||||
|
}; |
||||||
|
|
||||||
|
~ServerConfigSelector() override = default; |
||||||
|
// Returns the CallConfig to apply to a call based on the incoming \a metadata
|
||||||
|
virtual CallConfig GetCallConfig(grpc_metadata_batch* metadata) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
// ServerConfigSelectorProvider allows for subscribers to watch for updates on
|
||||||
|
// ServerConfigSelector. It is propagated via channel args.
|
||||||
|
class ServerConfigSelectorProvider |
||||||
|
: public RefCounted<ServerConfigSelectorProvider> { |
||||||
|
public: |
||||||
|
class ServerConfigSelectorWatcher { |
||||||
|
public: |
||||||
|
virtual ~ServerConfigSelectorWatcher() = default; |
||||||
|
virtual void OnServerConfigSelectorUpdate( |
||||||
|
absl::StatusOr<RefCountedPtr<ServerConfigSelector>> update) = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
~ServerConfigSelectorProvider() override = default; |
||||||
|
// Only a single watcher is allowed at present
|
||||||
|
virtual absl::StatusOr<RefCountedPtr<ServerConfigSelector>> Watch( |
||||||
|
std::unique_ptr<ServerConfigSelectorWatcher> watcher) = 0; |
||||||
|
virtual void CancelWatch() = 0; |
||||||
|
|
||||||
|
grpc_arg MakeChannelArg() const; |
||||||
|
static RefCountedPtr<ServerConfigSelectorProvider> GetFromChannelArgs( |
||||||
|
const grpc_channel_args& args); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_CORE_EXT_FILTERS_SERVER_CONFIG_SELECTOR_SERVER_CONFIG_SELECTOR_H
|
@ -0,0 +1,265 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// 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/server_config_selector/server_config_selector_filter.h" |
||||||
|
|
||||||
|
#include "src/core/ext/filters/server_config_selector/server_config_selector.h" |
||||||
|
#include "src/core/ext/service_config/service_config_call_data.h" |
||||||
|
#include "src/core/lib/transport/error_utils.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
class ChannelData { |
||||||
|
public: |
||||||
|
static grpc_error_handle Init(grpc_channel_element* elem, |
||||||
|
grpc_channel_element_args* args); |
||||||
|
static void Destroy(grpc_channel_element* elem); |
||||||
|
|
||||||
|
absl::StatusOr<RefCountedPtr<ServerConfigSelector>> config_selector() { |
||||||
|
MutexLock lock(&mu_); |
||||||
|
return config_selector_; |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
class ServerConfigSelectorWatcher |
||||||
|
: public ServerConfigSelectorProvider::ServerConfigSelectorWatcher { |
||||||
|
public: |
||||||
|
explicit ServerConfigSelectorWatcher(ChannelData* chand) : chand_(chand) {} |
||||||
|
void OnServerConfigSelectorUpdate( |
||||||
|
absl::StatusOr<RefCountedPtr<ServerConfigSelector>> update) override { |
||||||
|
MutexLock lock(&chand_->mu_); |
||||||
|
chand_->config_selector_ = std::move(update); |
||||||
|
} |
||||||
|
|
||||||
|
private: |
||||||
|
ChannelData* chand_; |
||||||
|
}; |
||||||
|
|
||||||
|
explicit ChannelData(RefCountedPtr<ServerConfigSelectorProvider> |
||||||
|
server_config_selector_provider); |
||||||
|
~ChannelData(); |
||||||
|
|
||||||
|
RefCountedPtr<ServerConfigSelectorProvider> server_config_selector_provider_; |
||||||
|
Mutex mu_; |
||||||
|
absl::StatusOr<RefCountedPtr<ServerConfigSelector>> config_selector_ |
||||||
|
ABSL_GUARDED_BY(mu_); |
||||||
|
}; |
||||||
|
|
||||||
|
class CallData { |
||||||
|
public: |
||||||
|
static grpc_error_handle Init(grpc_call_element* elem, |
||||||
|
const grpc_call_element_args* args); |
||||||
|
static void Destroy(grpc_call_element* elem, |
||||||
|
const grpc_call_final_info* /* final_info */, |
||||||
|
grpc_closure* /* then_schedule_closure */); |
||||||
|
static void StartTransportStreamOpBatch(grpc_call_element* elem, |
||||||
|
grpc_transport_stream_op_batch* op); |
||||||
|
|
||||||
|
private: |
||||||
|
CallData(grpc_call_element* elem, const grpc_call_element_args& args); |
||||||
|
~CallData(); |
||||||
|
static void RecvInitialMetadataReady(void* user_data, |
||||||
|
grpc_error_handle error); |
||||||
|
static void RecvTrailingMetadataReady(void* user_data, |
||||||
|
grpc_error_handle error); |
||||||
|
void MaybeResumeRecvTrailingMetadataReady(); |
||||||
|
|
||||||
|
grpc_call_context_element* call_context_; |
||||||
|
grpc_core::CallCombiner* call_combiner_; |
||||||
|
ServiceConfigCallData service_config_call_data_; |
||||||
|
// Overall error for the call
|
||||||
|
grpc_error_handle error_ = GRPC_ERROR_NONE; |
||||||
|
// State for keeping track of recv_initial_metadata
|
||||||
|
grpc_metadata_batch* recv_initial_metadata_ = nullptr; |
||||||
|
grpc_closure* original_recv_initial_metadata_ready_ = nullptr; |
||||||
|
grpc_closure recv_initial_metadata_ready_; |
||||||
|
// State for keeping of track of recv_trailing_metadata
|
||||||
|
grpc_closure* original_recv_trailing_metadata_ready_; |
||||||
|
grpc_closure recv_trailing_metadata_ready_; |
||||||
|
grpc_error_handle recv_trailing_metadata_ready_error_; |
||||||
|
bool seen_recv_trailing_metadata_ready_ = false; |
||||||
|
}; |
||||||
|
|
||||||
|
// ChannelData
|
||||||
|
|
||||||
|
grpc_error_handle ChannelData::Init(grpc_channel_element* elem, |
||||||
|
grpc_channel_element_args* args) { |
||||||
|
GPR_ASSERT(elem->filter = &kServerConfigSelectorFilter); |
||||||
|
RefCountedPtr<ServerConfigSelectorProvider> server_config_selector_provider = |
||||||
|
ServerConfigSelectorProvider::GetFromChannelArgs(*args->channel_args); |
||||||
|
if (server_config_selector_provider == nullptr) { |
||||||
|
return GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
||||||
|
"No ServerConfigSelectorProvider object found"); |
||||||
|
} |
||||||
|
new (elem->channel_data) |
||||||
|
ChannelData(std::move(server_config_selector_provider)); |
||||||
|
return GRPC_ERROR_NONE; |
||||||
|
} |
||||||
|
|
||||||
|
void ChannelData::Destroy(grpc_channel_element* elem) { |
||||||
|
auto* chand = static_cast<ChannelData*>(elem->channel_data); |
||||||
|
chand->~ChannelData(); |
||||||
|
} |
||||||
|
|
||||||
|
ChannelData::ChannelData( |
||||||
|
RefCountedPtr<ServerConfigSelectorProvider> server_config_selector_provider) |
||||||
|
: server_config_selector_provider_( |
||||||
|
std::move(server_config_selector_provider)) { |
||||||
|
GPR_ASSERT(server_config_selector_provider_ != nullptr); |
||||||
|
auto server_config_selector_watcher = |
||||||
|
absl::make_unique<ServerConfigSelectorWatcher>(this); |
||||||
|
config_selector_ = server_config_selector_provider_->Watch( |
||||||
|
std::move(server_config_selector_watcher)); |
||||||
|
} |
||||||
|
|
||||||
|
ChannelData::~ChannelData() { server_config_selector_provider_->CancelWatch(); } |
||||||
|
|
||||||
|
// CallData
|
||||||
|
|
||||||
|
grpc_error_handle CallData::Init(grpc_call_element* elem, |
||||||
|
const grpc_call_element_args* args) { |
||||||
|
new (elem->call_data) CallData(elem, *args); |
||||||
|
return GRPC_ERROR_NONE; |
||||||
|
} |
||||||
|
|
||||||
|
void CallData::Destroy(grpc_call_element* elem, |
||||||
|
const grpc_call_final_info* /*final_info*/, |
||||||
|
grpc_closure* /*then_schedule_closure*/) { |
||||||
|
auto* calld = static_cast<CallData*>(elem->call_data); |
||||||
|
calld->~CallData(); |
||||||
|
} |
||||||
|
|
||||||
|
void CallData::StartTransportStreamOpBatch(grpc_call_element* elem, |
||||||
|
grpc_transport_stream_op_batch* op) { |
||||||
|
CallData* calld = static_cast<CallData*>(elem->call_data); |
||||||
|
if (op->recv_initial_metadata) { |
||||||
|
calld->recv_initial_metadata_ = |
||||||
|
op->payload->recv_initial_metadata.recv_initial_metadata; |
||||||
|
calld->original_recv_initial_metadata_ready_ = |
||||||
|
op->payload->recv_initial_metadata.recv_initial_metadata_ready; |
||||||
|
op->payload->recv_initial_metadata.recv_initial_metadata_ready = |
||||||
|
&calld->recv_initial_metadata_ready_; |
||||||
|
} |
||||||
|
if (op->recv_trailing_metadata) { |
||||||
|
// We might generate errors on receiving initial metadata which we need to
|
||||||
|
// bubble up through recv_trailing_metadata_ready
|
||||||
|
calld->original_recv_trailing_metadata_ready_ = |
||||||
|
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready; |
||||||
|
op->payload->recv_trailing_metadata.recv_trailing_metadata_ready = |
||||||
|
&calld->recv_trailing_metadata_ready_; |
||||||
|
} |
||||||
|
// Chain to the next filter.
|
||||||
|
grpc_call_next_op(elem, op); |
||||||
|
} |
||||||
|
|
||||||
|
CallData::CallData(grpc_call_element* elem, const grpc_call_element_args& args) |
||||||
|
: call_context_(args.context), call_combiner_(args.call_combiner) { |
||||||
|
GRPC_CLOSURE_INIT(&recv_initial_metadata_ready_, RecvInitialMetadataReady, |
||||||
|
elem, grpc_schedule_on_exec_ctx); |
||||||
|
GRPC_CLOSURE_INIT(&recv_trailing_metadata_ready_, RecvTrailingMetadataReady, |
||||||
|
elem, grpc_schedule_on_exec_ctx); |
||||||
|
} |
||||||
|
|
||||||
|
CallData::~CallData() { |
||||||
|
// Remove the entry from call context, just in case anyone above us
|
||||||
|
// tries to look at it during call stack destruction.
|
||||||
|
call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value = nullptr; |
||||||
|
GRPC_ERROR_UNREF(error_); |
||||||
|
} |
||||||
|
|
||||||
|
void CallData::RecvInitialMetadataReady(void* user_data, |
||||||
|
grpc_error_handle error) { |
||||||
|
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); |
||||||
|
CallData* calld = static_cast<CallData*>(elem->call_data); |
||||||
|
ChannelData* chand = static_cast<ChannelData*>(elem->channel_data); |
||||||
|
if (error == GRPC_ERROR_NONE) { |
||||||
|
auto config_selector = chand->config_selector(); |
||||||
|
if (config_selector.ok()) { |
||||||
|
auto call_config = |
||||||
|
config_selector.value()->GetCallConfig(calld->recv_initial_metadata_); |
||||||
|
if (call_config.error != GRPC_ERROR_NONE) { |
||||||
|
calld->error_ = call_config.error; |
||||||
|
error = call_config.error; // Does not take a ref
|
||||||
|
} else { |
||||||
|
calld->service_config_call_data_ = |
||||||
|
ServiceConfigCallData(std::move(call_config.service_config), |
||||||
|
call_config.method_configs, {}); |
||||||
|
calld->call_context_[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA].value = |
||||||
|
&calld->service_config_call_data_; |
||||||
|
} |
||||||
|
} else { |
||||||
|
calld->error_ = absl_status_to_grpc_error(config_selector.status()); |
||||||
|
error = calld->error_; |
||||||
|
} |
||||||
|
} |
||||||
|
calld->MaybeResumeRecvTrailingMetadataReady(); |
||||||
|
grpc_closure* closure = calld->original_recv_initial_metadata_ready_; |
||||||
|
calld->original_recv_initial_metadata_ready_ = nullptr; |
||||||
|
Closure::Run(DEBUG_LOCATION, closure, GRPC_ERROR_REF(error)); |
||||||
|
} |
||||||
|
|
||||||
|
void CallData::RecvTrailingMetadataReady(void* user_data, |
||||||
|
grpc_error_handle error) { |
||||||
|
grpc_call_element* elem = static_cast<grpc_call_element*>(user_data); |
||||||
|
CallData* calld = static_cast<CallData*>(elem->call_data); |
||||||
|
if (calld->original_recv_initial_metadata_ready_ != nullptr) { |
||||||
|
calld->seen_recv_trailing_metadata_ready_ = true; |
||||||
|
calld->recv_trailing_metadata_ready_error_ = GRPC_ERROR_REF(error); |
||||||
|
GRPC_CALL_COMBINER_STOP(calld->call_combiner_, |
||||||
|
"Deferring RecvTrailingMetadataReady until after " |
||||||
|
"RecvInitialMetadataReady"); |
||||||
|
return; |
||||||
|
} |
||||||
|
error = grpc_error_add_child(GRPC_ERROR_REF(error), calld->error_); |
||||||
|
calld->error_ = GRPC_ERROR_NONE; |
||||||
|
grpc_closure* closure = calld->original_recv_trailing_metadata_ready_; |
||||||
|
calld->original_recv_trailing_metadata_ready_ = nullptr; |
||||||
|
Closure::Run(DEBUG_LOCATION, closure, error); |
||||||
|
} |
||||||
|
|
||||||
|
void CallData::MaybeResumeRecvTrailingMetadataReady() { |
||||||
|
if (seen_recv_trailing_metadata_ready_) { |
||||||
|
seen_recv_trailing_metadata_ready_ = false; |
||||||
|
grpc_error_handle error = recv_trailing_metadata_ready_error_; |
||||||
|
recv_trailing_metadata_ready_error_ = GRPC_ERROR_NONE; |
||||||
|
GRPC_CALL_COMBINER_START(call_combiner_, &recv_trailing_metadata_ready_, |
||||||
|
error, "Continuing RecvTrailingMetadataReady"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const grpc_channel_filter kServerConfigSelectorFilter = { |
||||||
|
CallData::StartTransportStreamOpBatch, |
||||||
|
grpc_channel_next_op, |
||||||
|
sizeof(CallData), |
||||||
|
CallData::Init, |
||||||
|
grpc_call_stack_ignore_set_pollset_or_pollset_set, |
||||||
|
CallData::Destroy, |
||||||
|
sizeof(ChannelData), |
||||||
|
ChannelData::Init, |
||||||
|
ChannelData::Destroy, |
||||||
|
grpc_channel_next_get_info, |
||||||
|
"server_config_selector_filter", |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,32 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_FILTERS_SERVER_CONFIG_SELECTOR_SERVER_CONFIG_SELECTOR_FILTER_H |
||||||
|
#define GRPC_CORE_EXT_FILTERS_SERVER_CONFIG_SELECTOR_SERVER_CONFIG_SELECTOR_FILTER_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/channel/channel_stack.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
extern const grpc_channel_filter kServerConfigSelectorFilter; |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_CORE_EXT_FILTERS_SERVER_CONFIG_SELECTOR_SERVER_CONFIG_SELECTOR_FILTER_H
|
@ -0,0 +1,35 @@ |
|||||||
|
# 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. |
||||||
|
|
||||||
|
load("//bazel:grpc_build_system.bzl", "grpc_cc_test", "grpc_package") |
||||||
|
|
||||||
|
licenses(["notice"]) |
||||||
|
|
||||||
|
grpc_package(name = "test/core/server_config_selector") |
||||||
|
|
||||||
|
grpc_cc_test( |
||||||
|
name = "server_config_selector_test", |
||||||
|
srcs = ["server_config_selector_test.cc"], |
||||||
|
external_deps = [ |
||||||
|
"gtest", |
||||||
|
], |
||||||
|
language = "C++", |
||||||
|
uses_polling = False, |
||||||
|
deps = [ |
||||||
|
"//:gpr", |
||||||
|
"//:grpc", |
||||||
|
"//:grpc_server_config_selector", |
||||||
|
"//test/core/util:grpc_test_util", |
||||||
|
], |
||||||
|
) |
@ -0,0 +1,81 @@ |
|||||||
|
//
|
||||||
|
//
|
||||||
|
// 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 "src/core/ext/filters/server_config_selector/server_config_selector.h" |
||||||
|
|
||||||
|
#include <gtest/gtest.h> |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
namespace grpc { |
||||||
|
namespace testing { |
||||||
|
namespace { |
||||||
|
|
||||||
|
using grpc_core::ServerConfigSelector; |
||||||
|
using grpc_core::ServerConfigSelectorProvider; |
||||||
|
|
||||||
|
class TestServerConfigSelectorProvider : public ServerConfigSelectorProvider { |
||||||
|
absl::StatusOr<grpc_core::RefCountedPtr<ServerConfigSelector>> Watch( |
||||||
|
std::unique_ptr<ServerConfigSelectorWatcher> /* watcher */) override { |
||||||
|
return absl::UnavailableError("Test ServerConfigSelector"); |
||||||
|
} |
||||||
|
|
||||||
|
void CancelWatch() override {} |
||||||
|
}; |
||||||
|
|
||||||
|
// Test that ServerConfigSelectorProvider can be safely copied to channel args
|
||||||
|
// and destroyed
|
||||||
|
TEST(ServerConfigSelectorProviderTest, CopyChannelArgs) { |
||||||
|
auto server_config_selector_provider = |
||||||
|
grpc_core::MakeRefCounted<TestServerConfigSelectorProvider>(); |
||||||
|
grpc_arg arg = server_config_selector_provider->MakeChannelArg(); |
||||||
|
grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); |
||||||
|
EXPECT_EQ(server_config_selector_provider, |
||||||
|
ServerConfigSelectorProvider::GetFromChannelArgs(*args)); |
||||||
|
grpc_channel_args_destroy(args); |
||||||
|
} |
||||||
|
|
||||||
|
// Test compare on channel args with the same ServerConfigSelectorProvider
|
||||||
|
TEST(ServerConfigSelectorProviderTest, ChannelArgsCompare) { |
||||||
|
auto server_config_selector_provider = |
||||||
|
grpc_core::MakeRefCounted<TestServerConfigSelectorProvider>(); |
||||||
|
grpc_arg arg = server_config_selector_provider->MakeChannelArg(); |
||||||
|
grpc_channel_args* args = grpc_channel_args_copy_and_add(nullptr, &arg, 1); |
||||||
|
grpc_channel_args* new_args = grpc_channel_args_copy(args); |
||||||
|
EXPECT_EQ(ServerConfigSelectorProvider::GetFromChannelArgs(*new_args), |
||||||
|
ServerConfigSelectorProvider::GetFromChannelArgs(*args)); |
||||||
|
grpc_channel_args_destroy(args); |
||||||
|
grpc_channel_args_destroy(new_args); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace testing
|
||||||
|
} // namespace grpc
|
||||||
|
|
||||||
|
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; |
||||||
|
} |
Loading…
Reference in new issue