mirror of https://github.com/grpc/grpc.git
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