Introduce the xds_override_host policy (#31730)
Introduce the xds_override_host policyreviewable/pr31717/r8^2
parent
1d968a36aa
commit
1e13612d4a
23 changed files with 872 additions and 24 deletions
@ -0,0 +1,410 @@ |
||||
//
|
||||
// Copyright 2022 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 <inttypes.h> |
||||
#include <string.h> |
||||
|
||||
#include <algorithm> |
||||
#include <memory> |
||||
#include <string> |
||||
#include <utility> |
||||
#include <vector> |
||||
|
||||
#include "absl/status/status.h" |
||||
#include "absl/status/statusor.h" |
||||
#include "absl/strings/str_cat.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/types/optional.h" |
||||
|
||||
#include <grpc/impl/codegen/connectivity_state.h> |
||||
#include <grpc/impl/codegen/grpc_types.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" |
||||
#include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" |
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/config/core_configuration.h" |
||||
#include "src/core/lib/debug/trace.h" |
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/gprpp/debug_location.h" |
||||
#include "src/core/lib/gprpp/orphanable.h" |
||||
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||
#include "src/core/lib/iomgr/pollset_set.h" |
||||
#include "src/core/lib/json/json.h" |
||||
#include "src/core/lib/json/json_args.h" |
||||
#include "src/core/lib/json/json_object_loader.h" |
||||
#include "src/core/lib/load_balancing/lb_policy.h" |
||||
#include "src/core/lib/load_balancing/lb_policy_factory.h" |
||||
#include "src/core/lib/load_balancing/subchannel_interface.h" |
||||
#include "src/core/lib/resolver/server_address.h" |
||||
#include "src/core/lib/transport/connectivity_state.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
TraceFlag grpc_lb_xds_override_host_trace(false, "xds_override_host_lb"); |
||||
|
||||
namespace { |
||||
|
||||
//
|
||||
// xds_override_host LB policy
|
||||
//
|
||||
|
||||
constexpr absl::string_view kXdsOverrideHost = "xds_override_host_experimental"; |
||||
|
||||
// Config for stateful session LB policy.
|
||||
class XdsOverrideHostLbConfig : public LoadBalancingPolicy::Config { |
||||
public: |
||||
XdsOverrideHostLbConfig() = default; |
||||
|
||||
XdsOverrideHostLbConfig(const XdsOverrideHostLbConfig&) = delete; |
||||
XdsOverrideHostLbConfig& operator=(const XdsOverrideHostLbConfig&) = delete; |
||||
|
||||
XdsOverrideHostLbConfig(XdsOverrideHostLbConfig&& other) = delete; |
||||
XdsOverrideHostLbConfig& operator=(XdsOverrideHostLbConfig&& other) = delete; |
||||
|
||||
absl::string_view name() const override { return kXdsOverrideHost; } |
||||
|
||||
RefCountedPtr<LoadBalancingPolicy::Config> child_config() const { |
||||
return child_config_; |
||||
} |
||||
|
||||
static const JsonLoaderInterface* JsonLoader(const JsonArgs&); |
||||
void JsonPostLoad(const Json& json, const JsonArgs&, |
||||
ValidationErrors* errors); |
||||
|
||||
private: |
||||
RefCountedPtr<LoadBalancingPolicy::Config> child_config_; |
||||
}; |
||||
|
||||
// xDS Cluster Impl LB policy.
|
||||
class XdsOverrideHostLb : public LoadBalancingPolicy { |
||||
public: |
||||
explicit XdsOverrideHostLb(Args args); |
||||
|
||||
absl::string_view name() const override { return kXdsOverrideHost; } |
||||
|
||||
absl::Status UpdateLocked(UpdateArgs args) override; |
||||
void ExitIdleLocked() override; |
||||
void ResetBackoffLocked() override; |
||||
|
||||
private: |
||||
// A picker that wraps the picker from the child for cases when cookie is
|
||||
// present.
|
||||
class Picker : public SubchannelPicker { |
||||
public: |
||||
Picker(XdsOverrideHostLb* xds_override_host_lb, |
||||
RefCountedPtr<SubchannelPicker> picker); |
||||
|
||||
PickResult Pick(PickArgs args) override; |
||||
|
||||
private: |
||||
RefCountedPtr<SubchannelPicker> picker_; |
||||
}; |
||||
|
||||
class Helper : public ChannelControlHelper { |
||||
public: |
||||
explicit Helper(RefCountedPtr<XdsOverrideHostLb> xds_override_host_policy) |
||||
: xds_override_host_policy_(std::move(xds_override_host_policy)) {} |
||||
|
||||
~Helper() override { |
||||
xds_override_host_policy_.reset(DEBUG_LOCATION, "Helper"); |
||||
} |
||||
|
||||
RefCountedPtr<SubchannelInterface> CreateSubchannel( |
||||
ServerAddress address, const ChannelArgs& args) override; |
||||
void UpdateState(grpc_connectivity_state state, const absl::Status& status, |
||||
RefCountedPtr<SubchannelPicker> picker) override; |
||||
void RequestReresolution() override; |
||||
absl::string_view GetAuthority() override; |
||||
grpc_event_engine::experimental::EventEngine* GetEventEngine() override; |
||||
void AddTraceEvent(TraceSeverity severity, |
||||
absl::string_view message) override; |
||||
|
||||
private: |
||||
RefCountedPtr<XdsOverrideHostLb> xds_override_host_policy_; |
||||
}; |
||||
|
||||
~XdsOverrideHostLb() override; |
||||
|
||||
void ShutdownLocked() override; |
||||
|
||||
OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked( |
||||
const ChannelArgs& args); |
||||
|
||||
void MaybeUpdatePickerLocked(); |
||||
|
||||
// Current config from the resolver.
|
||||
RefCountedPtr<XdsOverrideHostLbConfig> config_; |
||||
|
||||
// Internal state.
|
||||
bool shutting_down_ = false; |
||||
|
||||
OrphanablePtr<LoadBalancingPolicy> child_policy_; |
||||
|
||||
// Latest state and picker reported by the child policy.
|
||||
grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE; |
||||
absl::Status status_; |
||||
RefCountedPtr<SubchannelPicker> picker_; |
||||
}; |
||||
|
||||
//
|
||||
// XdsOverrideHostLb::Picker
|
||||
//
|
||||
|
||||
XdsOverrideHostLb::Picker::Picker(XdsOverrideHostLb* xds_override_host_lb, |
||||
RefCountedPtr<SubchannelPicker> picker) |
||||
: picker_(std::move(picker)) { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, "[xds_override_host_lb %p] constructed new picker %p", |
||||
xds_override_host_lb, this); |
||||
} |
||||
} |
||||
|
||||
LoadBalancingPolicy::PickResult XdsOverrideHostLb::Picker::Pick( |
||||
LoadBalancingPolicy::PickArgs args) { |
||||
if (picker_ == nullptr) { // Should never happen.
|
||||
return PickResult::Fail(absl::InternalError( |
||||
"xds_override_host picker not given any child picker")); |
||||
} |
||||
// Delegate to child picker
|
||||
return picker_->Pick(args); |
||||
} |
||||
|
||||
//
|
||||
// XdsOverrideHostLb
|
||||
//
|
||||
|
||||
XdsOverrideHostLb::XdsOverrideHostLb(Args args) |
||||
: LoadBalancingPolicy(std::move(args)) { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, "[xds_override_host_lb %p] created", this); |
||||
} |
||||
} |
||||
|
||||
XdsOverrideHostLb::~XdsOverrideHostLb() { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, |
||||
"[xds_override_host_lb %p] destroying xds_override_host LB policy", |
||||
this); |
||||
} |
||||
} |
||||
|
||||
void XdsOverrideHostLb::ShutdownLocked() { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, "[xds_override_host_lb %p] shutting down", this); |
||||
} |
||||
shutting_down_ = true; |
||||
// Remove the child policy's interested_parties pollset_set from the
|
||||
// xDS policy.
|
||||
if (child_policy_ != nullptr) { |
||||
grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(), |
||||
interested_parties()); |
||||
child_policy_.reset(); |
||||
} |
||||
// Drop our ref to the child's picker, in case it's holding a ref to
|
||||
// the child.
|
||||
picker_.reset(); |
||||
} |
||||
|
||||
void XdsOverrideHostLb::ExitIdleLocked() { |
||||
if (child_policy_ != nullptr) child_policy_->ExitIdleLocked(); |
||||
} |
||||
|
||||
void XdsOverrideHostLb::ResetBackoffLocked() { |
||||
if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked(); |
||||
} |
||||
|
||||
absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) { |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, "[xds_override_host_lb %p] Received update", this); |
||||
} |
||||
auto old_config = std::move(config_); |
||||
// Update config.
|
||||
config_ = std::move(args.config); |
||||
if (config_ == nullptr) { |
||||
return absl::InvalidArgumentError("Missing policy config"); |
||||
} |
||||
// Create child policy if needed.
|
||||
if (child_policy_ == nullptr) { |
||||
child_policy_ = CreateChildPolicyLocked(args.args); |
||||
} |
||||
// Update child policy.
|
||||
UpdateArgs update_args; |
||||
update_args.addresses = std::move(args.addresses); |
||||
update_args.resolution_note = std::move(args.resolution_note); |
||||
update_args.config = config_->child_config(); |
||||
update_args.args = std::move(args.args); |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, |
||||
"[xds_override_host_lb %p] Updating child policy handler %p", this, |
||||
child_policy_.get()); |
||||
} |
||||
return child_policy_->UpdateLocked(std::move(update_args)); |
||||
} |
||||
|
||||
void XdsOverrideHostLb::MaybeUpdatePickerLocked() { |
||||
if (picker_ != nullptr) { |
||||
auto xds_override_host_picker = MakeRefCounted<Picker>(this, picker_); |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, |
||||
"[xds_override_host_lb %p] updating connectivity: state=%s " |
||||
"status=(%s) picker=%p", |
||||
this, ConnectivityStateName(state_), status_.ToString().c_str(), |
||||
xds_override_host_picker.get()); |
||||
} |
||||
channel_control_helper()->UpdateState(state_, status_, |
||||
std::move(xds_override_host_picker)); |
||||
} |
||||
} |
||||
|
||||
OrphanablePtr<LoadBalancingPolicy> XdsOverrideHostLb::CreateChildPolicyLocked( |
||||
const ChannelArgs& args) { |
||||
LoadBalancingPolicy::Args lb_policy_args; |
||||
lb_policy_args.work_serializer = work_serializer(); |
||||
lb_policy_args.args = args; |
||||
lb_policy_args.channel_control_helper = |
||||
std::make_unique<Helper>(Ref(DEBUG_LOCATION, "Helper")); |
||||
OrphanablePtr<LoadBalancingPolicy> lb_policy = |
||||
MakeOrphanable<ChildPolicyHandler>(std::move(lb_policy_args), |
||||
&grpc_lb_xds_override_host_trace); |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, |
||||
"[xds_override_host_lb %p] Created new child policy handler %p", |
||||
this, lb_policy.get()); |
||||
} |
||||
// Add our interested_parties pollset_set to that of the newly created
|
||||
// child policy. This will make the child policy progress upon activity on
|
||||
// this policy, which in turn is tied to the application's call.
|
||||
grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(), |
||||
interested_parties()); |
||||
return lb_policy; |
||||
} |
||||
|
||||
//
|
||||
// XdsOverrideHostLb::Helper
|
||||
//
|
||||
|
||||
RefCountedPtr<SubchannelInterface> XdsOverrideHostLb::Helper::CreateSubchannel( |
||||
ServerAddress address, const ChannelArgs& args) { |
||||
return xds_override_host_policy_->channel_control_helper()->CreateSubchannel( |
||||
address, args); |
||||
} |
||||
|
||||
void XdsOverrideHostLb::Helper::UpdateState( |
||||
grpc_connectivity_state state, const absl::Status& status, |
||||
RefCountedPtr<SubchannelPicker> picker) { |
||||
if (xds_override_host_policy_->shutting_down_) return; |
||||
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
||||
gpr_log(GPR_INFO, |
||||
"[xds_override_host_lb %p] child connectivity state update: " |
||||
"state=%s (%s) picker=%p", |
||||
xds_override_host_policy_.get(), ConnectivityStateName(state), |
||||
status.ToString().c_str(), picker.get()); |
||||
} |
||||
// Save the state and picker.
|
||||
xds_override_host_policy_->state_ = state; |
||||
xds_override_host_policy_->status_ = status; |
||||
xds_override_host_policy_->picker_ = std::move(picker); |
||||
// Wrap the picker and return it to the channel.
|
||||
xds_override_host_policy_->MaybeUpdatePickerLocked(); |
||||
} |
||||
|
||||
void XdsOverrideHostLb::Helper::RequestReresolution() { |
||||
if (xds_override_host_policy_->shutting_down_) return; |
||||
xds_override_host_policy_->channel_control_helper()->RequestReresolution(); |
||||
} |
||||
|
||||
absl::string_view XdsOverrideHostLb::Helper::GetAuthority() { |
||||
return xds_override_host_policy_->channel_control_helper()->GetAuthority(); |
||||
} |
||||
|
||||
grpc_event_engine::experimental::EventEngine* |
||||
XdsOverrideHostLb::Helper::GetEventEngine() { |
||||
return xds_override_host_policy_->channel_control_helper()->GetEventEngine(); |
||||
} |
||||
|
||||
void XdsOverrideHostLb::Helper::AddTraceEvent(TraceSeverity severity, |
||||
absl::string_view message) { |
||||
if (xds_override_host_policy_->shutting_down_) return; |
||||
xds_override_host_policy_->channel_control_helper()->AddTraceEvent(severity, |
||||
message); |
||||
} |
||||
|
||||
//
|
||||
// factory
|
||||
//
|
||||
const JsonLoaderInterface* XdsOverrideHostLbConfig::JsonLoader( |
||||
const JsonArgs&) { |
||||
static const auto kJsonLoader = |
||||
JsonObjectLoader<XdsOverrideHostLbConfig>() |
||||
// Child policy config is parsed in JsonPostLoad
|
||||
.Finish(); |
||||
return kJsonLoader; |
||||
} |
||||
|
||||
void XdsOverrideHostLbConfig::JsonPostLoad(const Json& json, const JsonArgs&, |
||||
ValidationErrors* errors) { |
||||
ValidationErrors::ScopedField field(errors, ".childPolicy"); |
||||
auto it = json.object_value().find("childPolicy"); |
||||
if (it == json.object_value().end()) { |
||||
errors->AddError("field not present"); |
||||
} else { |
||||
auto child_policy_config = |
||||
CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig( |
||||
it->second); |
||||
if (!child_policy_config.ok()) { |
||||
errors->AddError(child_policy_config.status().message()); |
||||
} else { |
||||
child_config_ = std::move(*child_policy_config); |
||||
} |
||||
} |
||||
} |
||||
|
||||
class XdsOverrideHostLbFactory : public LoadBalancingPolicyFactory { |
||||
public: |
||||
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( |
||||
LoadBalancingPolicy::Args args) const override { |
||||
return MakeOrphanable<XdsOverrideHostLb>(std::move(args)); |
||||
} |
||||
|
||||
absl::string_view name() const override { return kXdsOverrideHost; } |
||||
|
||||
absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>> |
||||
ParseLoadBalancingConfig(const Json& json) const override { |
||||
if (json.type() == Json::Type::JSON_NULL) { |
||||
// This policy was configured in the deprecated loadBalancingPolicy
|
||||
// field or in the client API.
|
||||
return absl::InvalidArgumentError( |
||||
"field:loadBalancingPolicy error:xds_override_host policy requires " |
||||
"configuration. Please use loadBalancingConfig field of service " |
||||
"config instead."); |
||||
} |
||||
return LoadRefCountedFromJson<XdsOverrideHostLbConfig>( |
||||
json, JsonArgs(), |
||||
"errors validating xds_override_host LB policy config"); |
||||
} |
||||
}; |
||||
|
||||
} // namespace
|
||||
|
||||
void RegisterXdsOverrideHostLbPolicy(CoreConfiguration::Builder* builder) { |
||||
builder->lb_policy_registry()->RegisterLoadBalancingPolicyFactory( |
||||
std::make_unique<XdsOverrideHostLbFactory>()); |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,88 @@ |
||||
//
|
||||
// Copyright 2022 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 "gmock/gmock.h" |
||||
|
||||
#include "test/core/client_channel/lb_policy/lb_policy_test_lib.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace testing { |
||||
namespace { |
||||
|
||||
class XdsOverrideHostTest : public LoadBalancingPolicyTest { |
||||
protected: |
||||
XdsOverrideHostTest() |
||||
: policy_(MakeLbPolicy("xds_override_host_experimental")) {} |
||||
|
||||
RefCountedPtr<LoadBalancingPolicy::Config> MakeXdsOverrideHostConfig( |
||||
std::string child_policy = "pick_first") { |
||||
Json::Object child_policy_config = {{child_policy, Json::Object()}}; |
||||
return MakeConfig(Json::Array{Json::Object{ |
||||
{"xds_override_host_experimental", |
||||
Json::Object{{"childPolicy", Json::Array{{child_policy_config}}}}}}}); |
||||
} |
||||
|
||||
OrphanablePtr<LoadBalancingPolicy> policy_; |
||||
}; |
||||
|
||||
TEST_F(XdsOverrideHostTest, DelegatesToChild) { |
||||
ASSERT_NE(policy_, nullptr); |
||||
const std::array<absl::string_view, 2> kAddresses = {"ipv4:127.0.0.1:441", |
||||
"ipv4:127.0.0.1:442"}; |
||||
EXPECT_EQ(policy_->name(), "xds_override_host_experimental"); |
||||
// 1. We use pick_first as a child
|
||||
EXPECT_EQ(ApplyUpdate(BuildUpdate(kAddresses, MakeXdsOverrideHostConfig()), |
||||
policy_.get()), |
||||
absl::OkStatus()); |
||||
ExpectConnectingUpdate(); |
||||
auto subchannel = |
||||
FindSubchannel({kAddresses[0]}, |
||||
ChannelArgs().Set(GRPC_ARG_INHIBIT_HEALTH_CHECKING, true)); |
||||
ASSERT_NE(subchannel, nullptr); |
||||
ASSERT_TRUE(subchannel->ConnectionRequested()); |
||||
subchannel->SetConnectivityState(GRPC_CHANNEL_CONNECTING); |
||||
subchannel->SetConnectivityState(GRPC_CHANNEL_READY); |
||||
subchannel = |
||||
FindSubchannel({kAddresses[1]}, |
||||
ChannelArgs().Set(GRPC_ARG_INHIBIT_HEALTH_CHECKING, true)); |
||||
ASSERT_NE(subchannel, nullptr); |
||||
ASSERT_FALSE(subchannel->ConnectionRequested()); |
||||
auto picker = WaitForConnected(); |
||||
// Pick first policy will always pick first!
|
||||
EXPECT_EQ(ExpectPickComplete(picker.get()), "ipv4:127.0.0.1:441"); |
||||
EXPECT_EQ(ExpectPickComplete(picker.get()), "ipv4:127.0.0.1:441"); |
||||
} |
||||
|
||||
TEST_F(XdsOverrideHostTest, NoConfigReportsError) { |
||||
EXPECT_EQ( |
||||
ApplyUpdate(BuildUpdate({"ipv4:127.0.0.1:441", "ipv4:127.0.0.1:442"}), |
||||
policy_.get()), |
||||
absl::InvalidArgumentError("Missing policy config")); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
||||
|
||||
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; |
||||
} |
@ -0,0 +1,119 @@ |
||||
//
|
||||
// Copyright 2022 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 "absl/status/status.h" |
||||
#include "absl/status/statusor.h" |
||||
#include "gmock/gmock.h" |
||||
#include "gtest/gtest.h" |
||||
|
||||
#include <grpc/grpc.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/service_config/service_config.h" |
||||
#include "src/core/lib/service_config/service_config_impl.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
namespace grpc_core { |
||||
namespace testing { |
||||
namespace { |
||||
|
||||
TEST(XdsOverrideHostConfigParsingTest, ValidConfig) { |
||||
const char* service_config_json = |
||||
"{\n" |
||||
" \"loadBalancingConfig\":[{\n" |
||||
" \"xds_override_host_experimental\":{\n" |
||||
" \"childPolicy\":[\n" |
||||
" {\"grpclb\":{}}\n" |
||||
" ]\n" |
||||
" }\n" |
||||
" }]\n" |
||||
"}\n"; |
||||
auto service_config = |
||||
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); |
||||
ASSERT_TRUE(service_config.ok()); |
||||
EXPECT_NE(*service_config, nullptr); |
||||
} |
||||
|
||||
TEST(XdsOverrideHostConfigParsingTest, ReportsMissingChildPolicyField) { |
||||
const char* service_config_json = |
||||
"{\n" |
||||
" \"loadBalancingConfig\":[{\n" |
||||
" \"xds_override_host_experimental\":{\n" |
||||
" }\n" |
||||
" }]\n" |
||||
"}\n"; |
||||
auto service_config = |
||||
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); |
||||
ASSERT_FALSE(service_config.ok()); |
||||
EXPECT_EQ(service_config.status(), |
||||
absl::InvalidArgumentError( |
||||
"errors validating service config: [field:loadBalancingConfig " |
||||
"error:errors validating xds_override_host LB policy config: " |
||||
"[field:childPolicy error:field not present]]")); |
||||
} |
||||
|
||||
TEST(XdsOverrideHostConfigParsingTest, ReportsChildPolicyShouldBeArray) { |
||||
const char* service_config_json = |
||||
"{\n" |
||||
" \"loadBalancingConfig\":[{\n" |
||||
" \"xds_override_host_experimental\":{\n" |
||||
" \"childPolicy\":{\n" |
||||
" \"grpclb\":{},\n" |
||||
" }\n" |
||||
" }\n" |
||||
" }]\n" |
||||
"}\n"; |
||||
auto service_config = |
||||
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); |
||||
ASSERT_FALSE(service_config.ok()) << service_config.status(); |
||||
EXPECT_EQ(service_config.status(), |
||||
absl::InvalidArgumentError( |
||||
"errors validating service config: [field:loadBalancingConfig " |
||||
"error:errors validating xds_override_host LB policy config: " |
||||
"[field:childPolicy error:type should be array]]")); |
||||
} |
||||
|
||||
TEST(XdsOverrideHostConfigParsingTest, ReportsEmptyChildPolicyArray) { |
||||
const char* service_config_json = |
||||
"{\n" |
||||
" \"loadBalancingConfig\":[{\n" |
||||
" \"xds_override_host_experimental\":{\n" |
||||
" \"childPolicy\":[\n" |
||||
" ]\n" |
||||
" }\n" |
||||
" }]\n" |
||||
"}\n"; |
||||
auto service_config = |
||||
ServiceConfigImpl::Create(ChannelArgs(), service_config_json); |
||||
ASSERT_FALSE(service_config.ok()) << service_config.status(); |
||||
EXPECT_EQ(service_config.status(), |
||||
absl::InvalidArgumentError( |
||||
"errors validating service config: [field:loadBalancingConfig " |
||||
"error:errors validating xds_override_host LB policy config: " |
||||
"[field:childPolicy error:No known policies in list: ]]")); |
||||
} |
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc_core
|
||||
|
||||
int main(int argc, char** argv) { |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
grpc::testing::TestEnvironment env(&argc, argv); |
||||
grpc_init(); |
||||
auto result = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
return result; |
||||
} |
Loading…
Reference in new issue