1 //
2 //
3 // Copyright 2023 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18
19 #include "test/cpp/interop/rpc_behavior_lb_policy.h"
20
21 #include "absl/strings/str_format.h"
22
23 #include <grpc/support/port_platform.h>
24
25 #include "src/core/lib/iomgr/pollset_set.h"
26 #include "src/core/lib/json/json_args.h"
27 #include "src/core/lib/json/json_object_loader.h"
28 #include "src/core/load_balancing/delegating_helper.h"
29
30 namespace grpc {
31 namespace testing {
32
33 namespace {
34
35 using grpc_core::CoreConfiguration;
36 using grpc_core::Json;
37 using grpc_core::JsonArgs;
38 using grpc_core::JsonLoaderInterface;
39 using grpc_core::LoadBalancingPolicy;
40 using grpc_core::OrphanablePtr;
41 using grpc_core::RefCountedPtr;
42
43 constexpr absl::string_view kRpcBehaviorLbPolicyName =
44 "test.RpcBehaviorLoadBalancer";
45
46 constexpr absl::string_view kRpcBehaviorMetadataKey = "rpc-behavior";
47
48 class RpcBehaviorLbPolicyConfig : public LoadBalancingPolicy::Config {
49 public:
JsonLoader(const JsonArgs &)50 static JsonLoaderInterface* JsonLoader(const JsonArgs&) {
51 static const auto kJsonLoader =
52 grpc_core::JsonObjectLoader<RpcBehaviorLbPolicyConfig>()
53 .Field("rpcBehavior", &RpcBehaviorLbPolicyConfig::rpc_behavior_)
54 .Finish();
55 return kJsonLoader;
56 }
57
rpc_behavior() const58 absl::string_view rpc_behavior() const { return rpc_behavior_; }
59
60 private:
name() const61 absl::string_view name() const override { return kRpcBehaviorLbPolicyName; }
62
63 std::string rpc_behavior_;
64 };
65
66 class RpcBehaviorLbPolicy : public LoadBalancingPolicy {
67 public:
RpcBehaviorLbPolicy(Args args)68 explicit RpcBehaviorLbPolicy(Args args)
69 : LoadBalancingPolicy(std::move(args), /*initial_refcount=*/2) {
70 Args delegate_args;
71 delegate_args.work_serializer = work_serializer();
72 delegate_args.args = channel_args();
73 delegate_args.channel_control_helper =
74 std::make_unique<Helper>(RefCountedPtr<RpcBehaviorLbPolicy>(this));
75 delegate_ =
76 CoreConfiguration::Get().lb_policy_registry().CreateLoadBalancingPolicy(
77 "pick_first", std::move(delegate_args));
78 grpc_pollset_set_add_pollset_set(delegate_->interested_parties(),
79 interested_parties());
80 }
81
82 ~RpcBehaviorLbPolicy() override = default;
83
name() const84 absl::string_view name() const override { return kRpcBehaviorLbPolicyName; }
85
UpdateLocked(UpdateArgs args)86 absl::Status UpdateLocked(UpdateArgs args) override {
87 auto config = args.config.TakeAsSubclass<RpcBehaviorLbPolicyConfig>();
88 rpc_behavior_ = std::string(config->rpc_behavior());
89 // Use correct config for the delegate load balancing policy
90 auto delegate_config =
91 CoreConfiguration::Get().lb_policy_registry().ParseLoadBalancingConfig(
92 grpc_core::Json::FromArray({grpc_core::Json::FromObject(
93 {{std::string(delegate_->name()),
94 grpc_core::Json::FromObject({})}})}));
95 GPR_ASSERT(delegate_config.ok());
96 args.config = std::move(*delegate_config);
97 return delegate_->UpdateLocked(std::move(args));
98 }
99
ExitIdleLocked()100 void ExitIdleLocked() override { delegate_->ExitIdleLocked(); }
101
ResetBackoffLocked()102 void ResetBackoffLocked() override { delegate_->ResetBackoffLocked(); }
103
104 private:
105 class Picker : public SubchannelPicker {
106 public:
Picker(RefCountedPtr<SubchannelPicker> delegate_picker,absl::string_view rpc_behavior)107 Picker(RefCountedPtr<SubchannelPicker> delegate_picker,
108 absl::string_view rpc_behavior)
109 : delegate_picker_(std::move(delegate_picker)),
110 rpc_behavior_(rpc_behavior) {}
111
Pick(PickArgs args)112 PickResult Pick(PickArgs args) override {
113 char* rpc_behavior_copy = static_cast<char*>(
114 args.call_state->Alloc(rpc_behavior_.length() + 1));
115 strcpy(rpc_behavior_copy, rpc_behavior_.c_str());
116 args.initial_metadata->Add(kRpcBehaviorMetadataKey, rpc_behavior_copy);
117 // Do pick.
118 return delegate_picker_->Pick(args);
119 }
120
121 private:
122 RefCountedPtr<SubchannelPicker> delegate_picker_;
123 std::string rpc_behavior_;
124 };
125
126 class Helper
127 : public ParentOwningDelegatingChannelControlHelper<RpcBehaviorLbPolicy> {
128 public:
Helper(RefCountedPtr<RpcBehaviorLbPolicy> parent)129 explicit Helper(RefCountedPtr<RpcBehaviorLbPolicy> parent)
130 : ParentOwningDelegatingChannelControlHelper(std::move(parent)) {}
131
UpdateState(grpc_connectivity_state state,const absl::Status & status,RefCountedPtr<SubchannelPicker> picker)132 void UpdateState(grpc_connectivity_state state, const absl::Status& status,
133 RefCountedPtr<SubchannelPicker> picker) override {
134 parent_helper()->UpdateState(
135 state, status,
136 grpc_core::MakeRefCounted<Picker>(std::move(picker),
137 parent()->rpc_behavior_));
138 }
139 };
140
ShutdownLocked()141 void ShutdownLocked() override {
142 grpc_pollset_set_del_pollset_set(delegate_->interested_parties(),
143 interested_parties());
144 delegate_.reset();
145 }
146
147 OrphanablePtr<LoadBalancingPolicy> delegate_;
148 std::string rpc_behavior_;
149 };
150
151 class RpcBehaviorLbPolicyFactory
152 : public grpc_core::LoadBalancingPolicyFactory {
153 private:
name() const154 absl::string_view name() const override { return kRpcBehaviorLbPolicyName; }
155
CreateLoadBalancingPolicy(LoadBalancingPolicy::Args args) const156 grpc_core::OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
157 LoadBalancingPolicy::Args args) const override {
158 return grpc_core::MakeOrphanable<RpcBehaviorLbPolicy>(std::move(args));
159 }
160
161 absl::StatusOr<RefCountedPtr<LoadBalancingPolicy::Config>>
ParseLoadBalancingConfig(const Json & json) const162 ParseLoadBalancingConfig(const Json& json) const override {
163 return grpc_core::LoadFromJson<RefCountedPtr<RpcBehaviorLbPolicyConfig>>(
164 json, JsonArgs(), "errors validating LB policy config");
165 }
166 };
167 } // namespace
168
RegisterRpcBehaviorLbPolicy(grpc_core::CoreConfiguration::Builder * builder)169 void RegisterRpcBehaviorLbPolicy(
170 grpc_core::CoreConfiguration::Builder* builder) {
171 builder->lb_policy_registry()->RegisterLoadBalancingPolicyFactory(
172 std::make_unique<RpcBehaviorLbPolicyFactory>());
173 }
174
175 } // namespace testing
176 } // namespace grpc
177