• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "src/core/client_channel/client_channel_service_config.h"
18 
19 #include <grpc/grpc.h>
20 #include <grpc/slice.h>
21 
22 #include "absl/status/status.h"
23 #include "absl/status/statusor.h"
24 #include "gtest/gtest.h"
25 #include "src/core/config/core_configuration.h"
26 #include "src/core/lib/channel/channel_args.h"
27 #include "src/core/service_config/service_config.h"
28 #include "src/core/service_config/service_config_impl.h"
29 #include "src/core/service_config/service_config_parser.h"
30 #include "src/core/util/time.h"
31 #include "test/core/test_util/test_config.h"
32 
33 namespace grpc_core {
34 namespace testing {
35 
36 // A regular expression to enter referenced or child errors.
37 #define CHILD_ERROR_TAG ".*children.*"
38 
39 class ClientChannelParserTest : public ::testing::Test {
40  protected:
SetUp()41   void SetUp() override {
42     parser_index_ =
43         CoreConfiguration::Get().service_config_parser().GetParserIndex(
44             "client_channel");
45   }
46 
47   size_t parser_index_;
48 };
49 
TEST_F(ClientChannelParserTest,ValidLoadBalancingConfigPickFirst)50 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
51   const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}";
52   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
53   ASSERT_TRUE(service_config.ok()) << service_config.status();
54   const auto* parsed_config =
55       static_cast<internal::ClientChannelGlobalParsedConfig*>(
56           (*service_config)->GetGlobalParsedConfig(parser_index_));
57   auto lb_config = parsed_config->parsed_lb_config();
58   EXPECT_EQ(lb_config->name(), "pick_first");
59 }
60 
TEST_F(ClientChannelParserTest,ValidLoadBalancingConfigRoundRobin)61 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
62   const char* test_json =
63       "{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}";
64   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
65   ASSERT_TRUE(service_config.ok()) << service_config.status();
66   auto parsed_config = static_cast<internal::ClientChannelGlobalParsedConfig*>(
67       (*service_config)->GetGlobalParsedConfig(parser_index_));
68   auto lb_config = parsed_config->parsed_lb_config();
69   EXPECT_EQ(lb_config->name(), "round_robin");
70 }
71 
TEST_F(ClientChannelParserTest,ValidLoadBalancingConfigGrpclb)72 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
73   const char* test_json =
74       "{\"loadBalancingConfig\": "
75       "[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}";
76   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
77   ASSERT_TRUE(service_config.ok()) << service_config.status();
78   const auto* parsed_config =
79       static_cast<internal::ClientChannelGlobalParsedConfig*>(
80           (*service_config)->GetGlobalParsedConfig(parser_index_));
81   auto lb_config = parsed_config->parsed_lb_config();
82   EXPECT_EQ(lb_config->name(), "grpclb");
83 }
84 
TEST_F(ClientChannelParserTest,UnknownLoadBalancingConfig)85 TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
86   const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
87   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
88   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
89   EXPECT_EQ(service_config.status().message(),
90             "errors validating service config: ["
91             "field:loadBalancingConfig error:"
92             "No known policies in list: unknown]")
93       << service_config.status();
94 }
95 
TEST_F(ClientChannelParserTest,InvalidGrpclbLoadBalancingConfig)96 TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
97   const char* test_json =
98       "{\"loadBalancingConfig\": ["
99       "  {\"grpclb\":{\"childPolicy\":1}},"
100       "  {\"round_robin\":{}}"
101       "]}";
102   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
103   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
104   EXPECT_EQ(service_config.status().message(),
105             "errors validating service config: ["
106             "field:loadBalancingConfig error:"
107             "errors validating grpclb LB policy config: ["
108             "field:childPolicy error:type should be array]]")
109       << service_config.status();
110 }
111 
TEST_F(ClientChannelParserTest,ValidLoadBalancingPolicy)112 TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
113   const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}";
114   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
115   ASSERT_TRUE(service_config.ok()) << service_config.status();
116   const auto* parsed_config =
117       static_cast<internal::ClientChannelGlobalParsedConfig*>(
118           (*service_config)->GetGlobalParsedConfig(parser_index_));
119   EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
120 }
121 
TEST_F(ClientChannelParserTest,ValidLoadBalancingPolicyAllCaps)122 TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
123   const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}";
124   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
125   ASSERT_TRUE(service_config.ok()) << service_config.status();
126   const auto* parsed_config =
127       static_cast<internal::ClientChannelGlobalParsedConfig*>(
128           (*service_config)->GetGlobalParsedConfig(parser_index_));
129   EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
130 }
131 
TEST_F(ClientChannelParserTest,UnknownLoadBalancingPolicy)132 TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
133   const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}";
134   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
135   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
136   EXPECT_EQ(service_config.status().message(),
137             "errors validating service config: ["
138             "field:loadBalancingPolicy error:unknown LB policy \"unknown\"]")
139       << service_config.status();
140 }
141 
TEST_F(ClientChannelParserTest,LegacyLoadBalancingPolicySpecifiesPolicyThatRequiresConfig)142 TEST_F(ClientChannelParserTest,
143        LegacyLoadBalancingPolicySpecifiesPolicyThatRequiresConfig) {
144   const char* test_json = "{\"loadBalancingPolicy\":\"rls_experimental\"}";
145   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
146   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
147   EXPECT_EQ(service_config.status().message(),
148             "errors validating service config: ["
149             "field:loadBalancingPolicy error:LB policy "
150             "\"rls_experimental\" requires a config. Please "
151             "use loadBalancingConfig instead.]")
152       << service_config.status();
153 }
154 
TEST_F(ClientChannelParserTest,ValidTimeout)155 TEST_F(ClientChannelParserTest, ValidTimeout) {
156   const char* test_json =
157       "{\n"
158       "  \"methodConfig\": [ {\n"
159       "    \"name\": [\n"
160       "      { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
161       "    ],\n"
162       "    \"timeout\": \"5s\"\n"
163       "  } ]\n"
164       "}";
165   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
166   ASSERT_TRUE(service_config.ok()) << service_config.status();
167   const auto* vector_ptr =
168       (*service_config)
169           ->GetMethodParsedConfigVector(
170               grpc_slice_from_static_string("/TestServ/TestMethod"));
171   ASSERT_NE(vector_ptr, nullptr);
172   auto parsed_config = ((*vector_ptr)[parser_index_]).get();
173   EXPECT_EQ(
174       (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config))
175           ->timeout(),
176       Duration::Seconds(5));
177 }
178 
TEST_F(ClientChannelParserTest,InvalidTimeout)179 TEST_F(ClientChannelParserTest, InvalidTimeout) {
180   const char* test_json =
181       "{\n"
182       "  \"methodConfig\": [ {\n"
183       "    \"name\": [\n"
184       "      { \"service\": \"service\", \"method\": \"method\" }\n"
185       "    ],\n"
186       "    \"timeout\": \"5sec\"\n"
187       "  } ]\n"
188       "}";
189   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
190   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
191   EXPECT_EQ(service_config.status().message(),
192             "errors validating service config: ["
193             "field:methodConfig[0].timeout "
194             "error:Not a duration (no s suffix)]")
195       << service_config.status();
196 }
197 
TEST_F(ClientChannelParserTest,ValidWaitForReady)198 TEST_F(ClientChannelParserTest, ValidWaitForReady) {
199   const char* test_json =
200       "{\n"
201       "  \"methodConfig\": [ {\n"
202       "    \"name\": [\n"
203       "      { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
204       "    ],\n"
205       "    \"waitForReady\": true\n"
206       "  } ]\n"
207       "}";
208   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
209   ASSERT_TRUE(service_config.ok()) << service_config.status();
210   const auto* vector_ptr =
211       (*service_config)
212           ->GetMethodParsedConfigVector(
213               grpc_slice_from_static_string("/TestServ/TestMethod"));
214   ASSERT_NE(vector_ptr, nullptr);
215   auto parsed_config = ((*vector_ptr)[parser_index_]).get();
216   ASSERT_TRUE(
217       (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config))
218           ->wait_for_ready()
219           .has_value());
220   EXPECT_TRUE(
221       (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config))
222           ->wait_for_ready()
223           .value());
224 }
225 
TEST_F(ClientChannelParserTest,InvalidWaitForReady)226 TEST_F(ClientChannelParserTest, InvalidWaitForReady) {
227   const char* test_json =
228       "{\n"
229       "  \"methodConfig\": [ {\n"
230       "    \"name\": [\n"
231       "      { \"service\": \"service\", \"method\": \"method\" }\n"
232       "    ],\n"
233       "    \"waitForReady\": \"true\"\n"
234       "  } ]\n"
235       "}";
236   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
237   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
238   EXPECT_EQ(service_config.status().message(),
239             "errors validating service config: ["
240             "field:methodConfig[0].waitForReady error:is not a boolean]")
241       << service_config.status();
242 }
243 
TEST_F(ClientChannelParserTest,ValidHealthCheck)244 TEST_F(ClientChannelParserTest, ValidHealthCheck) {
245   const char* test_json =
246       "{\n"
247       "  \"healthCheckConfig\": {\n"
248       "    \"serviceName\": \"health_check_service_name\"\n"
249       "    }\n"
250       "}";
251   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
252   ASSERT_TRUE(service_config.ok()) << service_config.status();
253   const auto* parsed_config =
254       static_cast<internal::ClientChannelGlobalParsedConfig*>(
255           (*service_config)->GetGlobalParsedConfig(parser_index_));
256   ASSERT_NE(parsed_config, nullptr);
257   EXPECT_EQ(parsed_config->health_check_service_name(),
258             "health_check_service_name");
259 }
260 
TEST_F(ClientChannelParserTest,InvalidHealthCheckMultipleEntries)261 TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
262   const char* test_json =
263       "{\n"
264       "  \"healthCheckConfig\": {\n"
265       "    \"serviceName\": \"health_check_service_name\"\n"
266       "    },\n"
267       "  \"healthCheckConfig\": {\n"
268       "    \"serviceName\": \"health_check_service_name1\"\n"
269       "    }\n"
270       "}";
271   auto service_config = ServiceConfigImpl::Create(ChannelArgs(), test_json);
272   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
273   EXPECT_EQ(service_config.status().message(),
274             "JSON parsing failed: ["
275             "duplicate key \"healthCheckConfig\" at index 82]")
276       << service_config.status();
277 }
278 
279 }  // namespace testing
280 }  // namespace grpc_core
281 
main(int argc,char ** argv)282 int main(int argc, char** argv) {
283   ::testing::InitGoogleTest(&argc, argv);
284   grpc::testing::TestEnvironment env(&argc, argv);
285   grpc_init();
286   int ret = RUN_ALL_TESTS();
287   grpc_shutdown();
288   return ret;
289 }
290