1 // Copyright 2017 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15
16 #include <memory>
17
18 #include <gmock/gmock.h>
19 #include <gtest/gtest.h>
20
21 #include "absl/memory/memory.h"
22 #include "absl/strings/str_cat.h"
23
24 #include "src/core/client_channel/backup_poller.h"
25 #include "src/core/lib/config/config_vars.h"
26 #include "src/core/lib/gprpp/env.h"
27 #include "src/proto/grpc/lookup/v1/rls.grpc.pb.h"
28 #include "src/proto/grpc/lookup/v1/rls.pb.h"
29 #include "src/proto/grpc/lookup/v1/rls_config.pb.h"
30 #include "test/core/util/scoped_env_var.h"
31 #include "test/cpp/end2end/rls_server.h"
32 #include "test/cpp/end2end/xds/xds_end2end_test_lib.h"
33
34 namespace grpc {
35 namespace testing {
36 namespace {
37
38 using ::grpc::lookup::v1::RouteLookupClusterSpecifier;
39 using ::grpc::lookup::v1::RouteLookupConfig;
40
41 using ::grpc_core::testing::ScopedExperimentalEnvVar;
42
43 constexpr char kRlsTestKey[] = "test_key";
44 constexpr char kRlsTestKey1[] = "key1";
45 constexpr char kRlsTestValue[] = "test_value";
46 constexpr char kRlsHostKey[] = "host_key";
47 constexpr char kRlsServiceKey[] = "service_key";
48 constexpr char kRlsServiceValue[] = "grpc.testing.EchoTestService";
49 constexpr char kRlsMethodKey[] = "method_key";
50 constexpr char kRlsMethodValue[] = "Echo";
51 constexpr char kRlsConstantKey[] = "constant_key";
52 constexpr char kRlsConstantValue[] = "constant_value";
53 constexpr char kRlsClusterSpecifierPluginInstanceName[] = "rls_plugin_instance";
54
55 class RlsTest : public XdsEnd2endTest {
56 protected:
57 class RlsServerThread : public ServerThread {
58 public:
RlsServerThread(XdsEnd2endTest * test_obj)59 explicit RlsServerThread(XdsEnd2endTest* test_obj)
60 : ServerThread(test_obj, /*use_xds_enabled_server=*/false),
61 rls_service_(new RlsServiceImpl()) {}
62
rls_service()63 RlsServiceImpl* rls_service() { return rls_service_.get(); }
64
65 private:
Type()66 const char* Type() override { return "Rls"; }
67
RegisterAllServices(ServerBuilder * builder)68 void RegisterAllServices(ServerBuilder* builder) override {
69 builder->RegisterService(rls_service_.get());
70 }
71
StartAllServices()72 void StartAllServices() override { rls_service_->Start(); }
73
ShutdownAllServices()74 void ShutdownAllServices() override { rls_service_->Shutdown(); }
75
76 std::shared_ptr<RlsServiceImpl> rls_service_;
77 };
78
RlsTest()79 RlsTest() {
80 rls_server_ = std::make_unique<RlsServerThread>(this);
81 rls_server_->Start();
82 }
83
TearDown()84 void TearDown() override {
85 rls_server_->Shutdown();
86 XdsEnd2endTest::TearDown();
87 }
88
89 std::unique_ptr<RlsServerThread> rls_server_;
90 };
91
92 // Test both with and without RDS.
93 INSTANTIATE_TEST_SUITE_P(
94 XdsTest, RlsTest,
95 ::testing::Values(XdsTestType(), XdsTestType().set_enable_rds_testing()),
96 &XdsTestType::Name);
97
TEST_P(RlsTest,XdsRoutingClusterSpecifierPlugin)98 TEST_P(RlsTest, XdsRoutingClusterSpecifierPlugin) {
99 ScopedExperimentalEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB");
100 CreateAndStartBackends(2);
101 const char* kNewClusterName = "new_cluster";
102 const char* kNewEdsServiceName = "new_eds_service_name";
103 const size_t kNumEchoRpcs = 5;
104 // Populate new EDS resources.
105 EdsResourceArgs args({
106 {"locality0", CreateEndpointsForBackends(0, 1)},
107 });
108 EdsResourceArgs args1({
109 {"locality0", CreateEndpointsForBackends(1, 2)},
110 });
111 balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
112 balancer_->ads_service()->SetEdsResource(
113 BuildEdsResource(args1, kNewEdsServiceName));
114 // Populate new CDS resources.
115 Cluster new_cluster = default_cluster_;
116 new_cluster.set_name(kNewClusterName);
117 new_cluster.mutable_eds_cluster_config()->set_service_name(
118 kNewEdsServiceName);
119 balancer_->ads_service()->SetCdsResource(new_cluster);
120 // Prepare the RLSLookupConfig and configure all the keys; change route
121 // configurations to use cluster specifier plugin.
122 rls_server_->rls_service()->SetResponse(
123 BuildRlsRequest({{kRlsTestKey, kRlsTestValue},
124 {kRlsHostKey, kServerName},
125 {kRlsServiceKey, kRlsServiceValue},
126 {kRlsMethodKey, kRlsMethodValue},
127 {kRlsConstantKey, kRlsConstantValue}}),
128 BuildRlsResponse({kNewClusterName}));
129 RouteLookupConfig route_lookup_config;
130 auto* key_builder = route_lookup_config.add_grpc_keybuilders();
131 auto* name = key_builder->add_names();
132 name->set_service(kRlsServiceValue);
133 name->set_method(kRlsMethodValue);
134 auto* header = key_builder->add_headers();
135 header->set_key(kRlsTestKey);
136 header->add_names(kRlsTestKey1);
137 header->add_names("key2");
138 auto* extra_keys = key_builder->mutable_extra_keys();
139 extra_keys->set_host(kRlsHostKey);
140 extra_keys->set_service(kRlsServiceKey);
141 extra_keys->set_method(kRlsMethodKey);
142 (*key_builder->mutable_constant_keys())[kRlsConstantKey] = kRlsConstantValue;
143 route_lookup_config.set_lookup_service(
144 absl::StrCat("localhost:", rls_server_->port()));
145 route_lookup_config.set_cache_size_bytes(5000);
146 RouteLookupClusterSpecifier rls;
147 *rls.mutable_route_lookup_config() = std::move(route_lookup_config);
148 RouteConfiguration new_route_config = default_route_config_;
149 auto* plugin = new_route_config.add_cluster_specifier_plugins();
150 plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
151 plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
152 auto* default_route =
153 new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
154 default_route->mutable_route()->set_cluster_specifier_plugin(
155 kRlsClusterSpecifierPluginInstanceName);
156 SetRouteConfiguration(balancer_.get(), new_route_config);
157 auto rpc_options = RpcOptions().set_metadata({{kRlsTestKey1, kRlsTestValue}});
158 WaitForAllBackends(DEBUG_LOCATION, 1, 2, /*check_status=*/nullptr,
159 WaitForBackendOptions(), rpc_options);
160 CheckRpcSendOk(DEBUG_LOCATION, kNumEchoRpcs, rpc_options);
161 // Make sure RPCs all go to the correct backend.
162 EXPECT_EQ(kNumEchoRpcs, backends_[1]->backend_service()->request_count());
163 }
164
TEST_P(RlsTest,XdsRoutingClusterSpecifierPluginDisabled)165 TEST_P(RlsTest, XdsRoutingClusterSpecifierPluginDisabled) {
166 grpc_core::testing::ScopedEnvVar env_var("GRPC_EXPERIMENTAL_XDS_RLS_LB",
167 "false");
168 CreateAndStartBackends(1);
169 // Populate new EDS resources.
170 EdsResourceArgs args({{"locality0", CreateEndpointsForBackends()}});
171 balancer_->ads_service()->SetEdsResource(BuildEdsResource(args));
172 // Prepare the RLSLookupConfig and configure all the keys; change route
173 // configurations to use cluster specifier plugin.
174 RouteLookupConfig route_lookup_config;
175 auto* key_builder = route_lookup_config.add_grpc_keybuilders();
176 auto* name = key_builder->add_names();
177 name->set_service(kRlsServiceValue);
178 name->set_method(kRlsMethodValue);
179 auto* header = key_builder->add_headers();
180 header->set_key(kRlsTestKey);
181 header->add_names(kRlsTestKey1);
182 route_lookup_config.set_lookup_service(
183 absl::StrCat("localhost:", rls_server_->port()));
184 route_lookup_config.set_cache_size_bytes(5000);
185 RouteLookupClusterSpecifier rls;
186 *rls.mutable_route_lookup_config() = std::move(route_lookup_config);
187 RouteConfiguration new_route_config = default_route_config_;
188 auto* plugin = new_route_config.add_cluster_specifier_plugins();
189 plugin->mutable_extension()->set_name(kRlsClusterSpecifierPluginInstanceName);
190 plugin->mutable_extension()->mutable_typed_config()->PackFrom(rls);
191 auto* route = new_route_config.mutable_virtual_hosts(0)->mutable_routes(0);
192 route->mutable_route()->set_cluster_specifier_plugin(
193 kRlsClusterSpecifierPluginInstanceName);
194 auto* default_route = new_route_config.mutable_virtual_hosts(0)->add_routes();
195 default_route->mutable_match()->set_prefix("");
196 default_route->mutable_route()->set_cluster(kDefaultClusterName);
197 SetRouteConfiguration(balancer_.get(), new_route_config);
198 // Ensure we ignore the cluster specifier plugin and send traffic according to
199 // the default route.
200 auto rpc_options = RpcOptions().set_metadata({{kRlsTestKey1, kRlsTestValue}});
201 WaitForAllBackends(DEBUG_LOCATION, 0, 1, /*check_status=*/nullptr,
202 WaitForBackendOptions(), rpc_options);
203 }
204
205 } // namespace
206 } // namespace testing
207 } // namespace grpc
208
main(int argc,char ** argv)209 int main(int argc, char** argv) {
210 grpc::testing::TestEnvironment env(&argc, argv);
211 ::testing::InitGoogleTest(&argc, argv);
212 // Make the backup poller poll very frequently in order to pick up
213 // updates from all the subchannels's FDs.
214 grpc_core::ConfigVars::Overrides overrides;
215 overrides.client_channel_backup_poll_interval_ms = 1;
216 grpc_core::ConfigVars::SetOverrides(overrides);
217 #if TARGET_OS_IPHONE
218 // Workaround Apple CFStream bug
219 grpc_core::SetEnv("grpc_cfstream", "0");
220 #endif
221 grpc_init();
222 const auto result = RUN_ALL_TESTS();
223 grpc_shutdown();
224 return result;
225 }
226