• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 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 <grpc/grpc.h>
18 
19 #include <memory>
20 
21 #include "absl/status/status.h"
22 #include "absl/status/statusor.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "src/core/lib/channel/channel_args.h"
26 #include "src/core/service_config/service_config.h"
27 #include "src/core/service_config/service_config_impl.h"
28 #include "src/core/util/ref_counted_ptr.h"
29 #include "test/core/test_util/test_config.h"
30 
31 namespace grpc_core {
32 namespace {
33 
34 class RlsConfigParsingTest : public ::testing::Test {
35  public:
SetUpTestSuite()36   static void SetUpTestSuite() { grpc_init(); }
37 
TearDownTestSuite()38   static void TearDownTestSuite() { grpc_shutdown_blocking(); }
39 };
40 
TEST_F(RlsConfigParsingTest,ValidConfig)41 TEST_F(RlsConfigParsingTest, ValidConfig) {
42   const char* service_config_json =
43       "{\n"
44       "  \"loadBalancingConfig\":[{\n"
45       "    \"rls_experimental\":{\n"
46       "      \"routeLookupConfig\":{\n"
47       "        \"lookupService\":\"rls.example.com:80\",\n"
48       "        \"cacheSizeBytes\":1,\n"
49       "        \"grpcKeybuilders\":[\n"
50       "          {\n"
51       "            \"names\":[\n"
52       "              {\"service\":\"foo\"}\n"
53       "            ]\n"
54       "          }\n"
55       "        ]\n"
56       "      },\n"
57       "      \"routeLookupChannelServiceConfig\": {\n"
58       "        \"loadBalancingPolicy\": \"ROUND_ROBIN\"\n"
59       "      },\n"
60       "      \"childPolicy\":[\n"
61       "        {\"unknown\":{}},\n"  // Okay, since the next one exists.
62       "        {\"grpclb\":{}}\n"
63       "      ],\n"
64       "      \"childPolicyConfigTargetFieldName\":\"target\"\n"
65       "    }\n"
66       "  }]\n"
67       "}\n";
68   auto service_config =
69       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
70   ASSERT_TRUE(service_config.ok()) << service_config.status();
71   EXPECT_NE(*service_config, nullptr);
72 }
73 
74 //
75 // top-level fields
76 //
77 
TEST_F(RlsConfigParsingTest,TopLevelRequiredFieldsMissing)78 TEST_F(RlsConfigParsingTest, TopLevelRequiredFieldsMissing) {
79   const char* service_config_json =
80       "{\n"
81       "  \"loadBalancingConfig\":[{\n"
82       "    \"rls_experimental\":{\n"
83       "    }\n"
84       "  }]\n"
85       "}\n";
86   auto service_config =
87       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
88   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
89   EXPECT_THAT(
90       service_config.status().message(),
91       ::testing::HasSubstr(
92           "errors validating RLS LB policy config: ["
93           "field:childPolicy error:field not present; "
94           "field:childPolicyConfigTargetFieldName error:field not present; "
95           "field:routeLookupConfig error:field not present]"))
96       << service_config.status();
97 }
98 
TEST_F(RlsConfigParsingTest,TopLevelFieldsWrongTypes)99 TEST_F(RlsConfigParsingTest, TopLevelFieldsWrongTypes) {
100   const char* service_config_json =
101       "{\n"
102       "  \"loadBalancingConfig\":[{\n"
103       "    \"rls_experimental\":{\n"
104       "      \"routeLookupConfig\":1,\n"
105       "      \"routeLookupChannelServiceConfig\": 1,\n"
106       "      \"childPolicy\":1,\n"
107       "      \"childPolicyConfigTargetFieldName\":1\n"
108       "    }\n"
109       "  }]\n"
110       "}\n";
111   auto service_config =
112       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
113   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
114   EXPECT_EQ(service_config.status().message(),
115             "errors validating service config: ["
116             "field:loadBalancingConfig "
117             "error:errors validating RLS LB policy config: ["
118             "field:childPolicy error:is not an array; "
119             "field:childPolicyConfigTargetFieldName error:is not a string; "
120             "field:routeLookupChannelServiceConfig error:is not an object; "
121             "field:routeLookupConfig error:is not an object]]")
122       << service_config.status();
123 }
124 
TEST_F(RlsConfigParsingTest,TopLevelFieldsInvalidValues)125 TEST_F(RlsConfigParsingTest, TopLevelFieldsInvalidValues) {
126   const char* service_config_json =
127       "{\n"
128       "  \"loadBalancingConfig\":[{\n"
129       "    \"rls_experimental\":{\n"
130       "      \"childPolicy\":[\n"
131       "        {\"unknown\":{}}\n"
132       "      ],\n"
133       "      \"childPolicyConfigTargetFieldName\":\"\"\n"
134       "    }\n"
135       "  }]\n"
136       "}\n";
137   auto service_config =
138       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
139   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
140   EXPECT_THAT(
141       service_config.status().message(),
142       ::testing::HasSubstr(
143           "errors validating RLS LB policy config: ["
144           "field:childPolicy error:No known policies in list: unknown; "
145           "field:childPolicyConfigTargetFieldName error:must be non-empty; "
146           "field:routeLookupConfig error:field not present]"))
147       << service_config.status();
148 }
149 
TEST_F(RlsConfigParsingTest,InvalidChildPolicyConfig)150 TEST_F(RlsConfigParsingTest, InvalidChildPolicyConfig) {
151   const char* service_config_json =
152       "{\n"
153       "  \"loadBalancingConfig\":[{\n"
154       "    \"rls_experimental\":{\n"
155       "      \"childPolicy\":[\n"
156       "        {\"grpclb\":{\"childPolicy\":1}}\n"
157       "      ],\n"
158       "      \"childPolicyConfigTargetFieldName\":\"serviceName\"\n"
159       "    }\n"
160       "  }]\n"
161       "}\n";
162   auto service_config =
163       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
164   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
165   EXPECT_THAT(
166       service_config.status().message(),
167       ::testing::HasSubstr("errors validating RLS LB policy config: ["
168                            "field:childPolicy error:"
169                            "errors validating grpclb LB policy config: ["
170                            "field:childPolicy error:type should be array]; "
171                            "field:routeLookupConfig error:field not present]"))
172       << service_config.status();
173 }
174 
TEST_F(RlsConfigParsingTest,InvalidRlsChannelServiceConfig)175 TEST_F(RlsConfigParsingTest, InvalidRlsChannelServiceConfig) {
176   const char* service_config_json =
177       "{\n"
178       "  \"loadBalancingConfig\":[{\n"
179       "    \"rls_experimental\":{\n"
180       "      \"routeLookupChannelServiceConfig\": {\n"
181       "        \"loadBalancingPolicy\": \"unknown\"\n"
182       "      },\n"
183       "      \"childPolicy\":[\n"
184       "        {\"grpclb\":{}}\n"
185       "      ],\n"
186       "      \"childPolicyConfigTargetFieldName\":\"serviceName\"\n"
187       "    }\n"
188       "  }]\n"
189       "}\n";
190   auto service_config =
191       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
192   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
193   EXPECT_EQ(service_config.status().message(),
194             "errors validating service config: ["
195             "field:loadBalancingConfig "
196             "error:errors validating RLS LB policy config: ["
197             "field:routeLookupChannelServiceConfig.loadBalancingPolicy "
198             "error:unknown LB policy \"unknown\"; "
199             "field:routeLookupConfig error:field not present]]")
200       << service_config.status();
201 }
202 
203 //
204 // routeLookupConfig fields
205 //
206 
TEST_F(RlsConfigParsingTest,RouteLookupConfigRequiredFieldsMissing)207 TEST_F(RlsConfigParsingTest, RouteLookupConfigRequiredFieldsMissing) {
208   const char* service_config_json =
209       "{\n"
210       "  \"loadBalancingConfig\":[{\n"
211       "    \"rls_experimental\":{\n"
212       "      \"routeLookupConfig\":{\n"
213       "      }\n"
214       "    }\n"
215       "  }]\n"
216       "}\n";
217   auto service_config =
218       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
219   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
220   EXPECT_THAT(
221       service_config.status().message(),
222       ::testing::HasSubstr(
223           "errors validating RLS LB policy config: ["
224           "field:childPolicy error:field not present; "
225           "field:childPolicyConfigTargetFieldName error:field not present; "
226           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
227           "field:routeLookupConfig.grpcKeybuilders error:field not present; "
228           "field:routeLookupConfig.lookupService error:field not present]"))
229       << service_config.status();
230 }
231 
TEST_F(RlsConfigParsingTest,RouteLookupConfigFieldsWrongTypes)232 TEST_F(RlsConfigParsingTest, RouteLookupConfigFieldsWrongTypes) {
233   const char* service_config_json =
234       "{\n"
235       "  \"loadBalancingConfig\":[{\n"
236       "    \"rls_experimental\":{\n"
237       "      \"routeLookupConfig\":{\n"
238       "        \"grpcKeybuilders\":1,\n"
239       "        \"name\":1,\n"
240       "        \"lookupService\":1,\n"
241       "        \"lookupServiceTimeout\":{},\n"
242       "        \"maxAge\":{},\n"
243       "        \"staleAge\":{},\n"
244       "        \"cacheSizeBytes\":\"xxx\",\n"
245       "        \"defaultTarget\":1\n"
246       "      }\n"
247       "    }\n"
248       "  }]\n"
249       "}\n";
250   auto service_config =
251       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
252   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
253   EXPECT_THAT(
254       service_config.status().message(),
255       ::testing::HasSubstr(
256           "errors validating RLS LB policy config: ["
257           "field:childPolicy error:field not present; "
258           "field:childPolicyConfigTargetFieldName error:field not present; "
259           "field:routeLookupConfig.cacheSizeBytes error:"
260           "failed to parse number; "
261           "field:routeLookupConfig.defaultTarget error:is not a string; "
262           "field:routeLookupConfig.grpcKeybuilders error:is not an array; "
263           "field:routeLookupConfig.lookupService error:is not a string; "
264           "field:routeLookupConfig.lookupServiceTimeout error:is not a string; "
265           "field:routeLookupConfig.maxAge error:is not a string; "
266           "field:routeLookupConfig.staleAge error:is not a string]"))
267       << service_config.status();
268 }
269 
TEST_F(RlsConfigParsingTest,RouteLookupConfigFieldsInvalidValues)270 TEST_F(RlsConfigParsingTest, RouteLookupConfigFieldsInvalidValues) {
271   const char* service_config_json =
272       "{\n"
273       "  \"loadBalancingConfig\":[{\n"
274       "    \"rls_experimental\":{\n"
275       "      \"routeLookupConfig\":{\n"
276       "        \"lookupService\":\"\",\n"
277       "        \"cacheSizeBytes\":0\n"
278       "      }\n"
279       "    }\n"
280       "  }]\n"
281       "}\n";
282   auto service_config =
283       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
284   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
285   EXPECT_THAT(
286       service_config.status().message(),
287       ::testing::HasSubstr(
288           "errors validating RLS LB policy config: ["
289           "field:childPolicy error:field not present; "
290           "field:childPolicyConfigTargetFieldName error:field not present; "
291           "field:routeLookupConfig.cacheSizeBytes error:"
292           "must be greater than 0; "
293           "field:routeLookupConfig.grpcKeybuilders error:field not present; "
294           "field:routeLookupConfig.lookupService error:"
295           "must be valid gRPC target URI]"))
296       << service_config.status();
297 }
298 
299 //
300 // grpcKeybuilder fields
301 //
302 
TEST_F(RlsConfigParsingTest,GrpcKeybuilderRequiredFieldsMissing)303 TEST_F(RlsConfigParsingTest, GrpcKeybuilderRequiredFieldsMissing) {
304   const char* service_config_json =
305       "{\n"
306       "  \"loadBalancingConfig\":[{\n"
307       "    \"rls_experimental\":{\n"
308       "      \"routeLookupConfig\":{\n"
309       "        \"grpcKeybuilders\":[\n"
310       "          {\n"
311       "          }\n"
312       "        ]\n"
313       "      }\n"
314       "    }\n"
315       "  }]\n"
316       "}\n";
317   auto service_config =
318       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
319   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
320   EXPECT_THAT(
321       service_config.status().message(),
322       ::testing::HasSubstr(
323           "errors validating RLS LB policy config: ["
324           "field:childPolicy error:field not present; "
325           "field:childPolicyConfigTargetFieldName error:field not present; "
326           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
327           "field:routeLookupConfig.grpcKeybuilders[0].names error:"
328           "field not present; "
329           "field:routeLookupConfig.lookupService error:field not present]"))
330       << service_config.status();
331 }
332 
TEST_F(RlsConfigParsingTest,GrpcKeybuilderWrongFieldTypes)333 TEST_F(RlsConfigParsingTest, GrpcKeybuilderWrongFieldTypes) {
334   const char* service_config_json =
335       "{\n"
336       "  \"loadBalancingConfig\":[{\n"
337       "    \"rls_experimental\":{\n"
338       "      \"routeLookupConfig\":{\n"
339       "        \"grpcKeybuilders\":[\n"
340       "          {\n"
341       "            \"names\":1,\n"
342       "            \"headers\":1,\n"
343       "            \"extraKeys\":1,\n"
344       "            \"constantKeys\":1\n"
345       "          }\n"
346       "        ]\n"
347       "      }\n"
348       "    }\n"
349       "  }]\n"
350       "}\n";
351   auto service_config =
352       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
353   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
354   EXPECT_THAT(
355       service_config.status().message(),
356       ::testing::HasSubstr(
357           "errors validating RLS LB policy config: ["
358           "field:childPolicy error:field not present; "
359           "field:childPolicyConfigTargetFieldName error:field not present; "
360           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
361           "field:routeLookupConfig.grpcKeybuilders[0].constantKeys error:"
362           "is not an object; "
363           "field:routeLookupConfig.grpcKeybuilders[0].extraKeys error:"
364           "is not an object; "
365           "field:routeLookupConfig.grpcKeybuilders[0].headers error:"
366           "is not an array; "
367           "field:routeLookupConfig.grpcKeybuilders[0].names error:"
368           "is not an array; "
369           "field:routeLookupConfig.lookupService error:field not present]"))
370       << service_config.status();
371 }
372 
TEST_F(RlsConfigParsingTest,GrpcKeybuilderInvalidValues)373 TEST_F(RlsConfigParsingTest, GrpcKeybuilderInvalidValues) {
374   const char* service_config_json =
375       "{\n"
376       "  \"loadBalancingConfig\":[{\n"
377       "    \"rls_experimental\":{\n"
378       "      \"routeLookupConfig\":{\n"
379       "        \"grpcKeybuilders\":[\n"
380       "          {\n"
381       "            \"names\":[],\n"
382       "            \"extraKeys\":{\n"
383       "              \"host\":1,\n"
384       "              \"service\":1,\n"
385       "              \"method\":1\n"
386       "            },\n"
387       "            \"constantKeys\":{\n"
388       "              \"key\":1\n"
389       "            }\n"
390       "          }\n"
391       "        ]\n"
392       "      }\n"
393       "    }\n"
394       "  }]\n"
395       "}\n";
396   auto service_config =
397       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
398   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
399   EXPECT_THAT(
400       service_config.status().message(),
401       ::testing::HasSubstr(
402           "errors validating RLS LB policy config: ["
403           "field:childPolicy error:field not present; "
404           "field:childPolicyConfigTargetFieldName error:field not present; "
405           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
406           "field:routeLookupConfig.grpcKeybuilders[0].constantKeys[\"key\"] "
407           "error:is not a string; "
408           "field:routeLookupConfig.grpcKeybuilders[0].extraKeys.host "
409           "error:is not a string; "
410           "field:routeLookupConfig.grpcKeybuilders[0].extraKeys.method "
411           "error:is not a string; "
412           "field:routeLookupConfig.grpcKeybuilders[0].extraKeys.service "
413           "error:is not a string; "
414           "field:routeLookupConfig.grpcKeybuilders[0].names "
415           "error:must be non-empty; "
416           "field:routeLookupConfig.lookupService error:field not present]"))
417       << service_config.status();
418 }
419 
TEST_F(RlsConfigParsingTest,GrpcKeybuilderInvalidHeaders)420 TEST_F(RlsConfigParsingTest, GrpcKeybuilderInvalidHeaders) {
421   const char* service_config_json =
422       "{\n"
423       "  \"loadBalancingConfig\":[{\n"
424       "    \"rls_experimental\":{\n"
425       "      \"routeLookupConfig\":{\n"
426       "        \"grpcKeybuilders\":[\n"
427       "          {\n"
428       "            \"headers\":[\n"
429       "              1,\n"
430       "              {\n"
431       "                \"key\":1,\n"
432       "                \"names\":1\n"
433       "              },\n"
434       "              {\n"
435       "                \"names\":[]\n"
436       "              },\n"
437       "              {\n"
438       "                \"key\":\"\",\n"
439       "                \"names\":[1, \"\"]\n"
440       "              }\n"
441       "            ],\n"
442       "            \"extraKeys\":{\n"
443       "              \"host\": \"\"\n"
444       "            },\n"
445       "            \"constantKeys\":{\n"
446       "              \"\":\"foo\"\n"
447       "            }\n"
448       "          }\n"
449       "        ]\n"
450       "      }\n"
451       "    }\n"
452       "  }]\n"
453       "}\n";
454   auto service_config =
455       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
456   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
457   EXPECT_THAT(
458       service_config.status().message(),
459       ::testing::HasSubstr(
460           "errors validating RLS LB policy config: ["
461           "field:childPolicy error:field not present; "
462           "field:childPolicyConfigTargetFieldName error:field not present; "
463           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
464           "field:routeLookupConfig.grpcKeybuilders[0].constantKeys[\"\"] "
465           "error:key must be non-empty; "
466           "field:routeLookupConfig.grpcKeybuilders[0].extraKeys.host "
467           "error:must be non-empty if set; "
468           "field:routeLookupConfig.grpcKeybuilders[0].headers[0] "
469           "error:is not an object; "
470           "field:routeLookupConfig.grpcKeybuilders[0].headers[1].key "
471           "error:is not a string; "
472           "field:routeLookupConfig.grpcKeybuilders[0].headers[1].names "
473           "error:is not an array; "
474           "field:routeLookupConfig.grpcKeybuilders[0].headers[2].key "
475           "error:field not present; "
476           "field:routeLookupConfig.grpcKeybuilders[0].headers[2].names "
477           "error:must be non-empty; "
478           "field:routeLookupConfig.grpcKeybuilders[0].headers[3].key "
479           "error:must be non-empty; "
480           "field:routeLookupConfig.grpcKeybuilders[0].headers[3].names[0] "
481           "error:is not a string; "
482           "field:routeLookupConfig.grpcKeybuilders[0].headers[3].names[1] "
483           "error:must be non-empty; "
484           "field:routeLookupConfig.grpcKeybuilders[0].names "
485           "error:field not present; "
486           "field:routeLookupConfig.lookupService error:field not present]"))
487       << service_config.status();
488 }
489 
TEST_F(RlsConfigParsingTest,GrpcKeybuilderNameWrongFieldTypes)490 TEST_F(RlsConfigParsingTest, GrpcKeybuilderNameWrongFieldTypes) {
491   const char* service_config_json =
492       "{\n"
493       "  \"loadBalancingConfig\":[{\n"
494       "    \"rls_experimental\":{\n"
495       "      \"routeLookupConfig\":{\n"
496       "        \"grpcKeybuilders\":[\n"
497       "          {\n"
498       "            \"names\":[\n"
499       "              1,\n"
500       "              {\n"
501       "                \"service\":1,\n"
502       "                \"method\":1\n"
503       "              }\n"
504       "            ]\n"
505       "          }\n"
506       "        ]\n"
507       "      }\n"
508       "    }\n"
509       "  }]\n"
510       "}\n";
511   auto service_config =
512       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
513   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
514   EXPECT_THAT(
515       service_config.status().message(),
516       ::testing::HasSubstr(
517           "errors validating RLS LB policy config: ["
518           "field:childPolicy error:field not present; "
519           "field:childPolicyConfigTargetFieldName error:field not present; "
520           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
521           "field:routeLookupConfig.grpcKeybuilders[0].names[0] "
522           "error:is not an object; "
523           "field:routeLookupConfig.grpcKeybuilders[0].names[1].method "
524           "error:is not a string; "
525           "field:routeLookupConfig.grpcKeybuilders[0].names[1].service "
526           "error:is not a string; "
527           "field:routeLookupConfig.lookupService error:field not present]"))
528       << service_config.status();
529 }
530 
TEST_F(RlsConfigParsingTest,DuplicateMethodNamesInSameKeyBuilder)531 TEST_F(RlsConfigParsingTest, DuplicateMethodNamesInSameKeyBuilder) {
532   const char* service_config_json =
533       "{\n"
534       "  \"loadBalancingConfig\":[{\n"
535       "    \"rls_experimental\":{\n"
536       "      \"routeLookupConfig\":{\n"
537       "        \"grpcKeybuilders\":[\n"
538       "          {\n"
539       "            \"names\":[\n"
540       "              {\n"
541       "                \"service\":\"foo\",\n"
542       "                \"method\":\"bar\"\n"
543       "              },\n"
544       "              {\n"
545       "                \"service\":\"foo\",\n"
546       "                \"method\":\"bar\"\n"
547       "              }\n"
548       "            ]\n"
549       "          }\n"
550       "        ]\n"
551       "      }\n"
552       "    }\n"
553       "  }]\n"
554       "}\n";
555   auto service_config =
556       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
557   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
558   EXPECT_THAT(
559       service_config.status().message(),
560       ::testing::HasSubstr(
561           "errors validating RLS LB policy config: ["
562           "field:childPolicy error:field not present; "
563           "field:childPolicyConfigTargetFieldName error:field not present; "
564           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
565           "field:routeLookupConfig.grpcKeybuilders[0] "
566           "error:duplicate entry for \"/foo/bar\"; "
567           "field:routeLookupConfig.lookupService error:field not present]"))
568       << service_config.status();
569 }
570 
TEST_F(RlsConfigParsingTest,DuplicateMethodNamesInDifferentKeyBuilders)571 TEST_F(RlsConfigParsingTest, DuplicateMethodNamesInDifferentKeyBuilders) {
572   const char* service_config_json =
573       "{\n"
574       "  \"loadBalancingConfig\":[{\n"
575       "    \"rls_experimental\":{\n"
576       "      \"routeLookupConfig\":{\n"
577       "        \"grpcKeybuilders\":[\n"
578       "          {\n"
579       "            \"names\":[\n"
580       "              {\n"
581       "                \"service\":\"foo\",\n"
582       "                \"method\":\"bar\"\n"
583       "              }\n"
584       "            ]\n"
585       "          },\n"
586       "          {\n"
587       "            \"names\":[\n"
588       "              {\n"
589       "                \"service\":\"foo\",\n"
590       "                \"method\":\"bar\"\n"
591       "              }\n"
592       "            ]\n"
593       "          }\n"
594       "        ]\n"
595       "      }\n"
596       "    }\n"
597       "  }]\n"
598       "}\n";
599   auto service_config =
600       ServiceConfigImpl::Create(ChannelArgs(), service_config_json);
601   EXPECT_EQ(service_config.status().code(), absl::StatusCode::kInvalidArgument);
602   EXPECT_THAT(
603       service_config.status().message(),
604       ::testing::HasSubstr(
605           "errors validating RLS LB policy config: ["
606           "field:childPolicy error:field not present; "
607           "field:childPolicyConfigTargetFieldName error:field not present; "
608           "field:routeLookupConfig.cacheSizeBytes error:field not present; "
609           "field:routeLookupConfig.grpcKeybuilders[1] "
610           "error:duplicate entry for \"/foo/bar\"; "
611           "field:routeLookupConfig.lookupService error:field not present]"))
612       << service_config.status();
613 }
614 
615 }  // namespace
616 }  // namespace grpc_core
617 
main(int argc,char ** argv)618 int main(int argc, char** argv) {
619   ::testing::InitGoogleTest(&argc, argv);
620   grpc::testing::TestEnvironment env(&argc, argv);
621   return RUN_ALL_TESTS();
622 }
623