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