service_config_test.cc
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2019 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 
20 
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 
24 #include "absl/strings/str_cat.h"
25 
26 #include <grpc/grpc.h>
27 
35 #include "test/core/util/port.h"
37 
38 namespace grpc_core {
39 namespace testing {
40 
41 //
42 // ServiceConfig tests
43 //
44 
45 // Set this channel arg to true to disable parsing.
46 #define GRPC_ARG_DISABLE_PARSING "disable_parsing"
47 
48 // A regular expression to enter referenced or child errors.
49 #ifdef GRPC_ERROR_IS_ABSEIL_STATUS
50 #define CHILD_ERROR_TAG ".*children.*"
51 #else
52 #define CHILD_ERROR_TAG ".*referenced_errors.*"
53 #endif
54 
56  public:
57  explicit TestParsedConfig1(int value) : value_(value) {}
58 
59  int value() const { return value_; }
60 
61  private:
62  int value_;
63 };
64 
66  public:
67  absl::string_view name() const override { return "test_parser_1"; }
68 
69  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
70  const grpc_channel_args* args, const Json& json,
71  grpc_error_handle* error) override {
72  GPR_DEBUG_ASSERT(error != nullptr);
74  return nullptr;
75  }
76  auto it = json.object_value().find("global_param");
77  if (it != json.object_value().end()) {
78  if (it->second.type() != Json::Type::NUMBER) {
79  *error =
81  return nullptr;
82  }
83  int value = gpr_parse_nonnegative_int(it->second.string_value().c_str());
84  if (value == -1) {
85  *error =
87  return nullptr;
88  }
89  return absl::make_unique<TestParsedConfig1>(value);
90  }
91  return nullptr;
92  }
93 
94  static const char* InvalidTypeErrorMessage() {
95  return "global_param value type should be a number";
96  }
97 
98  static const char* InvalidValueErrorMessage() {
99  return "global_param value type should be non-negative";
100  }
101 };
102 
104  public:
105  absl::string_view name() const override { return "test_parser_2"; }
106 
107  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
108  const grpc_channel_args* args, const Json& json,
109  grpc_error_handle* error) override {
110  GPR_DEBUG_ASSERT(error != nullptr);
112  return nullptr;
113  }
114  auto it = json.object_value().find("method_param");
115  if (it != json.object_value().end()) {
116  if (it->second.type() != Json::Type::NUMBER) {
117  *error =
119  return nullptr;
120  }
121  int value = gpr_parse_nonnegative_int(it->second.string_value().c_str());
122  if (value == -1) {
123  *error =
125  return nullptr;
126  }
127  return absl::make_unique<TestParsedConfig1>(value);
128  }
129  return nullptr;
130  }
131 
132  static const char* InvalidTypeErrorMessage() {
133  return "method_param value type should be a number";
134  }
135 
136  static const char* InvalidValueErrorMessage() {
137  return "method_param value type should be non-negative";
138  }
139 };
140 
141 // This parser always adds errors
143  public:
145 
146  absl::string_view name() const override { return name_; }
147 
148  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParsePerMethodParams(
149  const grpc_channel_args* /*arg*/, const Json& /*json*/,
150  grpc_error_handle* error) override {
151  GPR_DEBUG_ASSERT(error != nullptr);
153  return nullptr;
154  }
155 
156  std::unique_ptr<ServiceConfigParser::ParsedConfig> ParseGlobalParams(
157  const grpc_channel_args* /*arg*/, const Json& /*json*/,
158  grpc_error_handle* error) override {
159  GPR_DEBUG_ASSERT(error != nullptr);
161  return nullptr;
162  }
163 
164  static const char* MethodError() { return "ErrorParser : methodError"; }
165 
166  static const char* GlobalError() { return "ErrorParser : globalError"; }
167 
168  private:
170 };
171 
173  protected:
174  void SetUp() override {
178  builder->service_config_parser()->RegisterParser(
179  absl::make_unique<TestParser1>());
180  builder->service_config_parser()->RegisterParser(
181  absl::make_unique<TestParser2>());
182  });
183  EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex(
184  "test_parser_1"),
185  0);
186  EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex(
187  "test_parser_2"),
188  1);
189  }
190 };
191 
192 TEST_F(ServiceConfigTest, ErrorCheck1) {
193  const char* test_json = "";
195  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
197  ::testing::ContainsRegex("JSON parse error"));
199 }
200 
201 TEST_F(ServiceConfigTest, BasicTest1) {
202  const char* test_json = "{}";
204  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
206 }
207 
208 TEST_F(ServiceConfigTest, SkipMethodConfigWithNoNameOrEmptyName) {
209  const char* test_json =
210  "{\"methodConfig\": ["
211  " {\"method_param\":1},"
212  " {\"name\":[], \"method_param\":1},"
213  " {\"name\":[{\"service\":\"TestServ\"}], \"method_param\":2}"
214  "]}";
216  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
218  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
219  grpc_slice_from_static_string("/TestServ/TestMethod"));
220  ASSERT_NE(vector_ptr, nullptr);
221  auto parsed_config = ((*vector_ptr)[1]).get();
222  EXPECT_EQ(static_cast<TestParsedConfig1*>(parsed_config)->value(), 2);
223 }
224 
225 TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNames) {
226  const char* test_json =
227  "{\"methodConfig\": ["
228  " {\"name\":[{\"service\":\"TestServ\"}]},"
229  " {\"name\":[{\"service\":\"TestServ\"}]}"
230  "]}";
232  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
235  "Service config parsing error" CHILD_ERROR_TAG
236  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
237  "multiple method configs with same name"));
239 }
240 
241 TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithNullMethod) {
242  const char* test_json =
243  "{\"methodConfig\": ["
244  " {\"name\":[{\"service\":\"TestServ\",\"method\":null}]},"
245  " {\"name\":[{\"service\":\"TestServ\"}]}"
246  "]}";
248  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
251  "Service config parsing error" CHILD_ERROR_TAG
252  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
253  "multiple method configs with same name"));
255 }
256 
257 TEST_F(ServiceConfigTest, ErrorDuplicateMethodConfigNamesWithEmptyMethod) {
258  const char* test_json =
259  "{\"methodConfig\": ["
260  " {\"name\":[{\"service\":\"TestServ\",\"method\":\"\"}]},"
261  " {\"name\":[{\"service\":\"TestServ\"}]}"
262  "]}";
264  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
267  "Service config parsing error" CHILD_ERROR_TAG
268  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
269  "multiple method configs with same name"));
271 }
272 
273 TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigs) {
274  const char* test_json =
275  "{\"methodConfig\": ["
276  " {\"name\":[{}]},"
277  " {\"name\":[{}]}"
278  "]}";
280  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
283  "Service config parsing error" CHILD_ERROR_TAG
284  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
285  "multiple default method configs"));
287 }
288 
289 TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithNullService) {
290  const char* test_json =
291  "{\"methodConfig\": ["
292  " {\"name\":[{\"service\":null}]},"
293  " {\"name\":[{}]}"
294  "]}";
296  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
299  "Service config parsing error" CHILD_ERROR_TAG
300  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
301  "multiple default method configs"));
303 }
304 
305 TEST_F(ServiceConfigTest, ErrorDuplicateDefaultMethodConfigsWithEmptyService) {
306  const char* test_json =
307  "{\"methodConfig\": ["
308  " {\"name\":[{\"service\":\"\"}]},"
309  " {\"name\":[{}]}"
310  "]}";
312  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
315  "Service config parsing error" CHILD_ERROR_TAG
316  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
317  "multiple default method configs"));
319 }
320 
321 TEST_F(ServiceConfigTest, ValidMethodConfig) {
322  const char* test_json =
323  "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}]}]}";
325  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
327 }
328 
329 TEST_F(ServiceConfigTest, Parser1BasicTest1) {
330  const char* test_json = "{\"global_param\":5}";
332  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
334  EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
335  ->value(),
336  5);
337  EXPECT_EQ(svc_cfg->GetMethodParsedConfigVector(
338  grpc_slice_from_static_string("/TestServ/TestMethod")),
339  nullptr);
340 }
341 
342 TEST_F(ServiceConfigTest, Parser1BasicTest2) {
343  const char* test_json = "{\"global_param\":1000}";
345  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
347  EXPECT_EQ((static_cast<TestParsedConfig1*>(svc_cfg->GetGlobalParsedConfig(0)))
348  ->value(),
349  1000);
350 }
351 
352 TEST_F(ServiceConfigTest, Parser1DisabledViaChannelArg) {
354  const_cast<char*>(GRPC_ARG_DISABLE_PARSING), 1);
355  grpc_channel_args args = {1, &arg};
356  const char* test_json = "{\"global_param\":5}";
358  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
360  EXPECT_EQ(svc_cfg->GetGlobalParsedConfig(0), nullptr);
361 }
362 
363 TEST_F(ServiceConfigTest, Parser1ErrorInvalidType) {
364  const char* test_json = "{\"global_param\":\"5\"}";
366  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
369  absl::StrCat("Service config parsing error" CHILD_ERROR_TAG
370  "Global Params" CHILD_ERROR_TAG,
373 }
374 
375 TEST_F(ServiceConfigTest, Parser1ErrorInvalidValue) {
376  const char* test_json = "{\"global_param\":-5}";
378  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
381  absl::StrCat("Service config parsing error" CHILD_ERROR_TAG
382  "Global Params" CHILD_ERROR_TAG,
385 }
386 
387 TEST_F(ServiceConfigTest, Parser2BasicTest) {
388  const char* test_json =
389  "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
390  "\"method_param\":5}]}";
392  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
394  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
395  grpc_slice_from_static_string("/TestServ/TestMethod"));
396  ASSERT_NE(vector_ptr, nullptr);
397  auto parsed_config = ((*vector_ptr)[1]).get();
398  EXPECT_EQ(static_cast<TestParsedConfig1*>(parsed_config)->value(), 5);
399 }
400 
401 TEST_F(ServiceConfigTest, Parser2DisabledViaChannelArg) {
403  const_cast<char*>(GRPC_ARG_DISABLE_PARSING), 1);
404  grpc_channel_args args = {1, &arg};
405  const char* test_json =
406  "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
407  "\"method_param\":5}]}";
409  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
411  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
412  grpc_slice_from_static_string("/TestServ/TestMethod"));
413  ASSERT_NE(vector_ptr, nullptr);
414  auto parsed_config = ((*vector_ptr)[1]).get();
415  EXPECT_EQ(parsed_config, nullptr);
416 }
417 
418 TEST_F(ServiceConfigTest, Parser2ErrorInvalidType) {
419  const char* test_json =
420  "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
421  "\"method_param\":\"5\"}]}";
423  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
424  EXPECT_THAT(
427  "Service config parsing error" CHILD_ERROR_TAG
428  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG,
431 }
432 
433 TEST_F(ServiceConfigTest, Parser2ErrorInvalidValue) {
434  const char* test_json =
435  "{\"methodConfig\": [{\"name\":[{\"service\":\"TestServ\"}], "
436  "\"method_param\":-5}]}";
438  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
439  EXPECT_THAT(
442  "Service config parsing error" CHILD_ERROR_TAG
443  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG,
446 }
447 
448 TEST(ServiceConfigParserTest, DoubleRegistration) {
453  builder->service_config_parser()->RegisterParser(
454  absl::make_unique<ErrorParser>("xyzabc"));
455  builder->service_config_parser()->RegisterParser(
456  absl::make_unique<ErrorParser>("xyzabc"));
457  }),
458  "xyzabc.*already registered");
459 }
460 
461 // Test parsing with ErrorParsers which always add errors
463  protected:
464  void SetUp() override {
468  builder->service_config_parser()->RegisterParser(
469  absl::make_unique<ErrorParser>("ep1"));
470  builder->service_config_parser()->RegisterParser(
471  absl::make_unique<ErrorParser>("ep2"));
472  });
473  EXPECT_EQ(
474  CoreConfiguration::Get().service_config_parser().GetParserIndex("ep1"),
475  0);
476  EXPECT_EQ(
477  CoreConfiguration::Get().service_config_parser().GetParserIndex("ep2"),
478  1);
479  }
480 };
481 
483  const char* test_json = "{}";
485  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
486  EXPECT_THAT(
489  "Service config parsing error" CHILD_ERROR_TAG
490  "Global Params" CHILD_ERROR_TAG,
493 }
494 
496  const char* test_json = "{\"methodConfig\": [{}]}";
498  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
499  EXPECT_THAT(
502  "Service config parsing error" CHILD_ERROR_TAG
503  "Global Params" CHILD_ERROR_TAG,
505  ".*Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG,
508 }
509 
510 //
511 // client_channel parser tests
512 //
513 
515  protected:
516  void SetUp() override {
520  builder->service_config_parser()->RegisterParser(
521  absl::make_unique<internal::ClientChannelServiceConfigParser>());
522  });
523  EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex(
524  "client_channel"),
525  0);
526  }
527 };
528 
529 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigPickFirst) {
530  const char* test_json = "{\"loadBalancingConfig\": [{\"pick_first\":{}}]}";
532  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
534  const auto* parsed_config =
536  svc_cfg->GetGlobalParsedConfig(0));
537  auto lb_config = parsed_config->parsed_lb_config();
538  EXPECT_STREQ(lb_config->name(), "pick_first");
539 }
540 
541 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigRoundRobin) {
542  const char* test_json =
543  "{\"loadBalancingConfig\": [{\"round_robin\":{}}, {}]}";
545  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
547  auto parsed_config = static_cast<internal::ClientChannelGlobalParsedConfig*>(
548  svc_cfg->GetGlobalParsedConfig(0));
549  auto lb_config = parsed_config->parsed_lb_config();
550  EXPECT_STREQ(lb_config->name(), "round_robin");
551 }
552 
553 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigGrpclb) {
554  const char* test_json =
555  "{\"loadBalancingConfig\": "
556  "[{\"grpclb\":{\"childPolicy\":[{\"pick_first\":{}}]}}]}";
558  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
560  const auto* parsed_config =
562  svc_cfg->GetGlobalParsedConfig(0));
563  auto lb_config = parsed_config->parsed_lb_config();
564  EXPECT_STREQ(lb_config->name(), "grpclb");
565 }
566 
567 TEST_F(ClientChannelParserTest, ValidLoadBalancingConfigXds) {
568  const char* test_json =
569  "{\n"
570  " \"loadBalancingConfig\":[\n"
571  " { \"does_not_exist\":{} },\n"
572  " { \"xds_cluster_resolver_experimental\":{\n"
573  " \"discoveryMechanisms\": [\n"
574  " { \"clusterName\": \"foo\",\n"
575  " \"type\": \"EDS\"\n"
576  " } ]\n"
577  " } }\n"
578  " ]\n"
579  "}";
581  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
583  const auto* parsed_config =
585  svc_cfg->GetGlobalParsedConfig(0));
586  auto lb_config = parsed_config->parsed_lb_config();
587  EXPECT_STREQ(lb_config->name(), "xds_cluster_resolver_experimental");
588 }
589 
590 TEST_F(ClientChannelParserTest, UnknownLoadBalancingConfig) {
591  const char* test_json = "{\"loadBalancingConfig\": [{\"unknown\":{}}]}";
593  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
594  EXPECT_THAT(
596  ::testing::ContainsRegex("Service config parsing error" CHILD_ERROR_TAG
597  "Global Params" CHILD_ERROR_TAG
598  "Client channel global parser" CHILD_ERROR_TAG
599  "field:loadBalancingConfig" CHILD_ERROR_TAG
600  "No known policies in list: unknown"));
602 }
603 
604 TEST_F(ClientChannelParserTest, InvalidGrpclbLoadBalancingConfig) {
605  const char* test_json =
606  "{\"loadBalancingConfig\": ["
607  " {\"grpclb\":{\"childPolicy\":1}},"
608  " {\"round_robin\":{}}"
609  "]}";
611  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
614  "Service config parsing error" CHILD_ERROR_TAG
615  "Global Params" CHILD_ERROR_TAG
616  "Client channel global parser" CHILD_ERROR_TAG
617  "field:loadBalancingConfig" CHILD_ERROR_TAG
618  "GrpcLb Parser" CHILD_ERROR_TAG
619  "field:childPolicy" CHILD_ERROR_TAG "type should be array"));
621 }
622 
623 TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicy) {
624  const char* test_json = "{\"loadBalancingPolicy\":\"pick_first\"}";
626  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
628  const auto* parsed_config =
630  svc_cfg->GetGlobalParsedConfig(0));
631  EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
632 }
633 
634 TEST_F(ClientChannelParserTest, ValidLoadBalancingPolicyAllCaps) {
635  const char* test_json = "{\"loadBalancingPolicy\":\"PICK_FIRST\"}";
637  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
639  const auto* parsed_config =
641  svc_cfg->GetGlobalParsedConfig(0));
642  EXPECT_EQ(parsed_config->parsed_deprecated_lb_policy(), "pick_first");
643 }
644 
645 TEST_F(ClientChannelParserTest, UnknownLoadBalancingPolicy) {
646  const char* test_json = "{\"loadBalancingPolicy\":\"unknown\"}";
648  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
651  "Service config parsing error" CHILD_ERROR_TAG
652  "Global Params" CHILD_ERROR_TAG
653  "Client channel global parser" CHILD_ERROR_TAG
654  "field:loadBalancingPolicy error:Unknown lb policy"));
656 }
657 
658 TEST_F(ClientChannelParserTest, LoadBalancingPolicyXdsNotAllowed) {
659  const char* test_json =
660  "{\"loadBalancingPolicy\":\"xds_cluster_resolver_experimental\"}";
662  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
665  "Service config parsing error" CHILD_ERROR_TAG
666  "Global Params" CHILD_ERROR_TAG
667  "Client channel global parser" CHILD_ERROR_TAG
668  "field:loadBalancingPolicy "
669  "error:xds_cluster_resolver_experimental requires "
670  "a config. Please use loadBalancingConfig instead."));
672 }
673 
675  const char* test_json =
676  "{\n"
677  " \"methodConfig\": [ {\n"
678  " \"name\": [\n"
679  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
680  " ],\n"
681  " \"timeout\": \"5s\"\n"
682  " } ]\n"
683  "}";
685  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
687  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
688  grpc_slice_from_static_string("/TestServ/TestMethod"));
689  ASSERT_NE(vector_ptr, nullptr);
690  auto parsed_config = ((*vector_ptr)[0]).get();
691  EXPECT_EQ(
692  (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config))
693  ->timeout(),
694  Duration::Seconds(5));
695 }
696 
697 TEST_F(ClientChannelParserTest, InvalidTimeout) {
698  const char* test_json =
699  "{\n"
700  " \"methodConfig\": [ {\n"
701  " \"name\": [\n"
702  " { \"service\": \"service\", \"method\": \"method\" }\n"
703  " ],\n"
704  " \"timeout\": \"5sec\"\n"
705  " } ]\n"
706  "}";
708  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
711  "Service config parsing error" CHILD_ERROR_TAG
712  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
713  "Client channel parser" CHILD_ERROR_TAG
714  "field:timeout error:type should be STRING of the form given "
715  "by google.proto.Duration"));
717 }
718 
719 TEST_F(ClientChannelParserTest, ValidWaitForReady) {
720  const char* test_json =
721  "{\n"
722  " \"methodConfig\": [ {\n"
723  " \"name\": [\n"
724  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
725  " ],\n"
726  " \"waitForReady\": true\n"
727  " } ]\n"
728  "}";
730  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
732  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
733  grpc_slice_from_static_string("/TestServ/TestMethod"));
734  ASSERT_NE(vector_ptr, nullptr);
735  auto parsed_config = ((*vector_ptr)[0]).get();
736  ASSERT_TRUE(
737  (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config))
738  ->wait_for_ready()
739  .has_value());
740  EXPECT_TRUE(
741  (static_cast<internal::ClientChannelMethodParsedConfig*>(parsed_config))
742  ->wait_for_ready()
743  .value());
744 }
745 
746 TEST_F(ClientChannelParserTest, InvalidWaitForReady) {
747  const char* test_json =
748  "{\n"
749  " \"methodConfig\": [ {\n"
750  " \"name\": [\n"
751  " { \"service\": \"service\", \"method\": \"method\" }\n"
752  " ],\n"
753  " \"waitForReady\": \"true\"\n"
754  " } ]\n"
755  "}";
757  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
760  "Service config parsing error" CHILD_ERROR_TAG
761  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
762  "Client channel parser" CHILD_ERROR_TAG
763  "field:waitForReady error:Type should be true/false"));
765 }
766 
767 TEST_F(ClientChannelParserTest, ValidHealthCheck) {
768  const char* test_json =
769  "{\n"
770  " \"healthCheckConfig\": {\n"
771  " \"serviceName\": \"health_check_service_name\"\n"
772  " }\n"
773  "}";
775  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
777  const auto* parsed_config =
779  svc_cfg->GetGlobalParsedConfig(0));
780  ASSERT_NE(parsed_config, nullptr);
781  EXPECT_EQ(parsed_config->health_check_service_name(),
782  "health_check_service_name");
783 }
784 
785 TEST_F(ClientChannelParserTest, InvalidHealthCheckMultipleEntries) {
786  const char* test_json =
787  "{\n"
788  " \"healthCheckConfig\": {\n"
789  " \"serviceName\": \"health_check_service_name\"\n"
790  " },\n"
791  " \"healthCheckConfig\": {\n"
792  " \"serviceName\": \"health_check_service_name1\"\n"
793  " }\n"
794  "}";
796  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
799  "JSON parsing failed" CHILD_ERROR_TAG
800  "duplicate key \"healthCheckConfig\" at index 104"));
802 }
803 
804 //
805 // retry parser tests
806 //
807 
809  protected:
810  void SetUp() override {
814  builder->service_config_parser()->RegisterParser(
815  absl::make_unique<internal::RetryServiceConfigParser>());
816  });
817  EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex(
818  "retry"),
819  0);
820  }
821 };
822 
823 TEST_F(RetryParserTest, ValidRetryThrottling) {
824  const char* test_json =
825  "{\n"
826  " \"retryThrottling\": {\n"
827  " \"maxTokens\": 2,\n"
828  " \"tokenRatio\": 1.0\n"
829  " }\n"
830  "}";
832  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
834  const auto* parsed_config = static_cast<internal::RetryGlobalConfig*>(
835  svc_cfg->GetGlobalParsedConfig(0));
836  ASSERT_NE(parsed_config, nullptr);
837  EXPECT_EQ(parsed_config->max_milli_tokens(), 2000);
838  EXPECT_EQ(parsed_config->milli_token_ratio(), 1000);
839 }
840 
841 TEST_F(RetryParserTest, RetryThrottlingMissingFields) {
842  const char* test_json =
843  "{\n"
844  " \"retryThrottling\": {\n"
845  " }\n"
846  "}";
848  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
849  EXPECT_THAT(
852  "Service config parsing error" CHILD_ERROR_TAG
853  "Global Params" CHILD_ERROR_TAG "retryThrottling" CHILD_ERROR_TAG
854  "field:retryThrottling field:maxTokens error:Not found"
855  ".*field:retryThrottling field:tokenRatio error:Not found"));
857 }
858 
859 TEST_F(RetryParserTest, InvalidRetryThrottlingNegativeMaxTokens) {
860  const char* test_json =
861  "{\n"
862  " \"retryThrottling\": {\n"
863  " \"maxTokens\": -2,\n"
864  " \"tokenRatio\": 1.0\n"
865  " }\n"
866  "}";
868  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
869  EXPECT_THAT(
872  "Service config parsing error" CHILD_ERROR_TAG
873  "Global Params" CHILD_ERROR_TAG "retryThrottling" CHILD_ERROR_TAG
874  "field:retryThrottling field:maxTokens error:should "
875  "be greater than zero"));
877 }
878 
879 TEST_F(RetryParserTest, InvalidRetryThrottlingInvalidTokenRatio) {
880  const char* test_json =
881  "{\n"
882  " \"retryThrottling\": {\n"
883  " \"maxTokens\": 2,\n"
884  " \"tokenRatio\": -1\n"
885  " }\n"
886  "}";
888  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
889  EXPECT_THAT(
891  ::testing::ContainsRegex("Service config parsing error" CHILD_ERROR_TAG
892  "Global Params" CHILD_ERROR_TAG
893  "retryThrottling" CHILD_ERROR_TAG
894  "field:retryThrottling field:tokenRatio "
895  "error:Failed parsing"));
897 }
898 
899 TEST_F(RetryParserTest, ValidRetryPolicy) {
900  const char* test_json =
901  "{\n"
902  " \"methodConfig\": [ {\n"
903  " \"name\": [\n"
904  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
905  " ],\n"
906  " \"retryPolicy\": {\n"
907  " \"maxAttempts\": 3,\n"
908  " \"initialBackoff\": \"1s\",\n"
909  " \"maxBackoff\": \"120s\",\n"
910  " \"backoffMultiplier\": 1.6,\n"
911  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
912  " }\n"
913  " } ]\n"
914  "}";
916  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
918  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
919  grpc_slice_from_static_string("/TestServ/TestMethod"));
920  ASSERT_NE(vector_ptr, nullptr);
921  const auto* parsed_config =
922  static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get());
923  ASSERT_NE(parsed_config, nullptr);
924  EXPECT_EQ(parsed_config->max_attempts(), 3);
925  EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1));
926  EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2));
927  EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f);
928  EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), absl::nullopt);
929  EXPECT_TRUE(
930  parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED));
931 }
932 
933 TEST_F(RetryParserTest, InvalidRetryPolicyWrongType) {
934  const char* test_json =
935  "{\n"
936  " \"methodConfig\": [ {\n"
937  " \"name\": [\n"
938  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
939  " ],\n"
940  " \"retryPolicy\": 5\n"
941  " } ]\n"
942  "}";
944  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
947  "Service config parsing error" CHILD_ERROR_TAG
948  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
949  "field:retryPolicy error:should be of type object"));
951 }
952 
953 TEST_F(RetryParserTest, InvalidRetryPolicyRequiredFieldsMissing) {
954  const char* test_json =
955  "{\n"
956  " \"methodConfig\": [ {\n"
957  " \"name\": [\n"
958  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
959  " ],\n"
960  " \"retryPolicy\": {\n"
961  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
962  " }\n"
963  " } ]\n"
964  "}";
966  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
969  "Service config parsing error" CHILD_ERROR_TAG
970  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
971  "retryPolicy" CHILD_ERROR_TAG
972  ".*field:maxAttempts error:required field missing"
973  ".*field:initialBackoff error:does not exist"
974  ".*field:maxBackoff error:does not exist"
975  ".*field:backoffMultiplier error:required field missing"));
977 }
978 
979 TEST_F(RetryParserTest, InvalidRetryPolicyMaxAttemptsWrongType) {
980  const char* test_json =
981  "{\n"
982  " \"methodConfig\": [ {\n"
983  " \"name\": [\n"
984  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
985  " ],\n"
986  " \"retryPolicy\": {\n"
987  " \"maxAttempts\": \"FOO\",\n"
988  " \"initialBackoff\": \"1s\",\n"
989  " \"maxBackoff\": \"120s\",\n"
990  " \"backoffMultiplier\": 1.6,\n"
991  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
992  " }\n"
993  " } ]\n"
994  "}";
996  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
999  "Service config parsing error" CHILD_ERROR_TAG
1000  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1001  "retryPolicy" CHILD_ERROR_TAG
1002  "field:maxAttempts error:should be of type number"));
1004 }
1005 
1006 TEST_F(RetryParserTest, InvalidRetryPolicyMaxAttemptsBadValue) {
1007  const char* test_json =
1008  "{\n"
1009  " \"methodConfig\": [ {\n"
1010  " \"name\": [\n"
1011  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1012  " ],\n"
1013  " \"retryPolicy\": {\n"
1014  " \"maxAttempts\": 1,\n"
1015  " \"initialBackoff\": \"1s\",\n"
1016  " \"maxBackoff\": \"120s\",\n"
1017  " \"backoffMultiplier\": 1.6,\n"
1018  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1019  " }\n"
1020  " } ]\n"
1021  "}";
1023  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1026  "Service config parsing error" CHILD_ERROR_TAG
1027  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1028  "retryPolicy" CHILD_ERROR_TAG
1029  "field:maxAttempts error:should be at least 2"));
1031 }
1032 
1033 TEST_F(RetryParserTest, InvalidRetryPolicyInitialBackoffWrongType) {
1034  const char* test_json =
1035  "{\n"
1036  " \"methodConfig\": [ {\n"
1037  " \"name\": [\n"
1038  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1039  " ],\n"
1040  " \"retryPolicy\": {\n"
1041  " \"maxAttempts\": 2,\n"
1042  " \"initialBackoff\": \"1sec\",\n"
1043  " \"maxBackoff\": \"120s\",\n"
1044  " \"backoffMultiplier\": 1.6,\n"
1045  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1046  " }\n"
1047  " } ]\n"
1048  "}";
1050  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1053  "Service config parsing error" CHILD_ERROR_TAG
1054  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1055  "retryPolicy" CHILD_ERROR_TAG
1056  "field:initialBackoff error:type should be STRING of the "
1057  "form given by google.proto.Duration"));
1059 }
1060 
1061 TEST_F(RetryParserTest, InvalidRetryPolicyInitialBackoffBadValue) {
1062  const char* test_json =
1063  "{\n"
1064  " \"methodConfig\": [ {\n"
1065  " \"name\": [\n"
1066  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1067  " ],\n"
1068  " \"retryPolicy\": {\n"
1069  " \"maxAttempts\": 2,\n"
1070  " \"initialBackoff\": \"0s\",\n"
1071  " \"maxBackoff\": \"120s\",\n"
1072  " \"backoffMultiplier\": 1.6,\n"
1073  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1074  " }\n"
1075  " } ]\n"
1076  "}";
1078  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1081  "Service config parsing error" CHILD_ERROR_TAG
1082  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1083  "retryPolicy" CHILD_ERROR_TAG
1084  "field:initialBackoff error:must be greater than 0"));
1086 }
1087 
1088 TEST_F(RetryParserTest, InvalidRetryPolicyMaxBackoffWrongType) {
1089  const char* test_json =
1090  "{\n"
1091  " \"methodConfig\": [ {\n"
1092  " \"name\": [\n"
1093  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1094  " ],\n"
1095  " \"retryPolicy\": {\n"
1096  " \"maxAttempts\": 2,\n"
1097  " \"initialBackoff\": \"1s\",\n"
1098  " \"maxBackoff\": \"120sec\",\n"
1099  " \"backoffMultiplier\": 1.6,\n"
1100  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1101  " }\n"
1102  " } ]\n"
1103  "}";
1105  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1108  "Service config parsing error" CHILD_ERROR_TAG
1109  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1110  "retryPolicy" CHILD_ERROR_TAG
1111  "field:maxBackoff error:type should be STRING of the form "
1112  "given by google.proto.Duration"));
1114 }
1115 
1116 TEST_F(RetryParserTest, InvalidRetryPolicyMaxBackoffBadValue) {
1117  const char* test_json =
1118  "{\n"
1119  " \"methodConfig\": [ {\n"
1120  " \"name\": [\n"
1121  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1122  " ],\n"
1123  " \"retryPolicy\": {\n"
1124  " \"maxAttempts\": 2,\n"
1125  " \"initialBackoff\": \"1s\",\n"
1126  " \"maxBackoff\": \"0s\",\n"
1127  " \"backoffMultiplier\": 1.6,\n"
1128  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1129  " }\n"
1130  " } ]\n"
1131  "}";
1133  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1136  "Service config parsing error" CHILD_ERROR_TAG
1137  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1138  "retryPolicy" CHILD_ERROR_TAG
1139  "field:maxBackoff error:must be greater than 0"));
1141 }
1142 
1143 TEST_F(RetryParserTest, InvalidRetryPolicyBackoffMultiplierWrongType) {
1144  const char* test_json =
1145  "{\n"
1146  " \"methodConfig\": [ {\n"
1147  " \"name\": [\n"
1148  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1149  " ],\n"
1150  " \"retryPolicy\": {\n"
1151  " \"maxAttempts\": 2,\n"
1152  " \"initialBackoff\": \"1s\",\n"
1153  " \"maxBackoff\": \"120s\",\n"
1154  " \"backoffMultiplier\": \"1.6\",\n"
1155  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1156  " }\n"
1157  " } ]\n"
1158  "}";
1160  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1163  "Service config parsing error" CHILD_ERROR_TAG
1164  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1165  "retryPolicy" CHILD_ERROR_TAG
1166  "field:backoffMultiplier error:should be of type number"));
1168 }
1169 
1170 TEST_F(RetryParserTest, InvalidRetryPolicyBackoffMultiplierBadValue) {
1171  const char* test_json =
1172  "{\n"
1173  " \"methodConfig\": [ {\n"
1174  " \"name\": [\n"
1175  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1176  " ],\n"
1177  " \"retryPolicy\": {\n"
1178  " \"maxAttempts\": 2,\n"
1179  " \"initialBackoff\": \"1s\",\n"
1180  " \"maxBackoff\": \"120s\",\n"
1181  " \"backoffMultiplier\": 0,\n"
1182  " \"retryableStatusCodes\": [ \"ABORTED\" ]\n"
1183  " }\n"
1184  " } ]\n"
1185  "}";
1187  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1190  "Service config parsing error" CHILD_ERROR_TAG
1191  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1192  "retryPolicy" CHILD_ERROR_TAG
1193  "field:backoffMultiplier error:must be greater than 0"));
1195 }
1196 
1197 TEST_F(RetryParserTest, InvalidRetryPolicyEmptyRetryableStatusCodes) {
1198  const char* test_json =
1199  "{\n"
1200  " \"methodConfig\": [ {\n"
1201  " \"name\": [\n"
1202  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1203  " ],\n"
1204  " \"retryPolicy\": {\n"
1205  " \"maxAttempts\": 2,\n"
1206  " \"initialBackoff\": \"1s\",\n"
1207  " \"maxBackoff\": \"120s\",\n"
1208  " \"backoffMultiplier\": \"1.6\",\n"
1209  " \"retryableStatusCodes\": []\n"
1210  " }\n"
1211  " } ]\n"
1212  "}";
1214  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1217  "Service config parsing error" CHILD_ERROR_TAG
1218  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1219  "retryPolicy" CHILD_ERROR_TAG
1220  "field:retryableStatusCodes error:must be non-empty"));
1222 }
1223 
1224 TEST_F(RetryParserTest, InvalidRetryPolicyRetryableStatusCodesWrongType) {
1225  const char* test_json =
1226  "{\n"
1227  " \"methodConfig\": [ {\n"
1228  " \"name\": [\n"
1229  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1230  " ],\n"
1231  " \"retryPolicy\": {\n"
1232  " \"maxAttempts\": 2,\n"
1233  " \"initialBackoff\": \"1s\",\n"
1234  " \"maxBackoff\": \"120s\",\n"
1235  " \"backoffMultiplier\": \"1.6\",\n"
1236  " \"retryableStatusCodes\": 0\n"
1237  " }\n"
1238  " } ]\n"
1239  "}";
1241  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1244  "Service config parsing error" CHILD_ERROR_TAG
1245  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1246  "retryPolicy" CHILD_ERROR_TAG
1247  "field:retryableStatusCodes error:must be of type array"));
1249 }
1250 
1251 TEST_F(RetryParserTest, InvalidRetryPolicyUnparseableRetryableStatusCodes) {
1252  const char* test_json =
1253  "{\n"
1254  " \"methodConfig\": [ {\n"
1255  " \"name\": [\n"
1256  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1257  " ],\n"
1258  " \"retryPolicy\": {\n"
1259  " \"maxAttempts\": 2,\n"
1260  " \"initialBackoff\": \"1s\",\n"
1261  " \"maxBackoff\": \"120s\",\n"
1262  " \"backoffMultiplier\": \"1.6\",\n"
1263  " \"retryableStatusCodes\": [\"FOO\", 2]\n"
1264  " }\n"
1265  " } ]\n"
1266  "}";
1268  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1271  "Service config parsing error" CHILD_ERROR_TAG
1272  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1273  "retryPolicy" CHILD_ERROR_TAG "field:retryableStatusCodes "
1274  "error:failed to parse status code"
1275  ".*field:retryableStatusCodes "
1276  "error:status codes should be of type string"));
1278 }
1279 
1280 TEST_F(RetryParserTest, ValidRetryPolicyWithPerAttemptRecvTimeout) {
1281  const char* test_json =
1282  "{\n"
1283  " \"methodConfig\": [ {\n"
1284  " \"name\": [\n"
1285  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1286  " ],\n"
1287  " \"retryPolicy\": {\n"
1288  " \"maxAttempts\": 2,\n"
1289  " \"initialBackoff\": \"1s\",\n"
1290  " \"maxBackoff\": \"120s\",\n"
1291  " \"backoffMultiplier\": 1.6,\n"
1292  " \"perAttemptRecvTimeout\": \"1s\",\n"
1293  " \"retryableStatusCodes\": [\"ABORTED\"]\n"
1294  " }\n"
1295  " } ]\n"
1296  "}";
1299  const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1);
1300  grpc_channel_args args = {1, &arg};
1301  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
1303  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
1304  grpc_slice_from_static_string("/TestServ/TestMethod"));
1305  ASSERT_NE(vector_ptr, nullptr);
1306  const auto* parsed_config =
1307  static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get());
1308  ASSERT_NE(parsed_config, nullptr);
1309  EXPECT_EQ(parsed_config->max_attempts(), 2);
1310  EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1));
1311  EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2));
1312  EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f);
1313  EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), Duration::Seconds(1));
1314  EXPECT_TRUE(
1315  parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED));
1316 }
1317 
1319  ValidRetryPolicyWithPerAttemptRecvTimeoutIgnoredWhenHedgingDisabled) {
1320  const char* test_json =
1321  "{\n"
1322  " \"methodConfig\": [ {\n"
1323  " \"name\": [\n"
1324  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1325  " ],\n"
1326  " \"retryPolicy\": {\n"
1327  " \"maxAttempts\": 2,\n"
1328  " \"initialBackoff\": \"1s\",\n"
1329  " \"maxBackoff\": \"120s\",\n"
1330  " \"backoffMultiplier\": 1.6,\n"
1331  " \"perAttemptRecvTimeout\": \"1s\",\n"
1332  " \"retryableStatusCodes\": [\"ABORTED\"]\n"
1333  " }\n"
1334  " } ]\n"
1335  "}";
1337  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1339  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
1340  grpc_slice_from_static_string("/TestServ/TestMethod"));
1341  ASSERT_NE(vector_ptr, nullptr);
1342  const auto* parsed_config =
1343  static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get());
1344  ASSERT_NE(parsed_config, nullptr);
1345  EXPECT_EQ(parsed_config->max_attempts(), 2);
1346  EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1));
1347  EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2));
1348  EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f);
1349  EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), absl::nullopt);
1350  EXPECT_TRUE(
1351  parsed_config->retryable_status_codes().Contains(GRPC_STATUS_ABORTED));
1352 }
1353 
1355  ValidRetryPolicyWithPerAttemptRecvTimeoutAndUnsetRetryableStatusCodes) {
1356  const char* test_json =
1357  "{\n"
1358  " \"methodConfig\": [ {\n"
1359  " \"name\": [\n"
1360  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1361  " ],\n"
1362  " \"retryPolicy\": {\n"
1363  " \"maxAttempts\": 2,\n"
1364  " \"initialBackoff\": \"1s\",\n"
1365  " \"maxBackoff\": \"120s\",\n"
1366  " \"backoffMultiplier\": 1.6,\n"
1367  " \"perAttemptRecvTimeout\": \"1s\"\n"
1368  " }\n"
1369  " } ]\n"
1370  "}";
1373  const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1);
1374  grpc_channel_args args = {1, &arg};
1375  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
1377  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
1378  grpc_slice_from_static_string("/TestServ/TestMethod"));
1379  ASSERT_NE(vector_ptr, nullptr);
1380  const auto* parsed_config =
1381  static_cast<internal::RetryMethodConfig*>(((*vector_ptr)[0]).get());
1382  ASSERT_NE(parsed_config, nullptr);
1383  EXPECT_EQ(parsed_config->max_attempts(), 2);
1384  EXPECT_EQ(parsed_config->initial_backoff(), Duration::Seconds(1));
1385  EXPECT_EQ(parsed_config->max_backoff(), Duration::Minutes(2));
1386  EXPECT_EQ(parsed_config->backoff_multiplier(), 1.6f);
1387  EXPECT_EQ(parsed_config->per_attempt_recv_timeout(), Duration::Seconds(1));
1388  EXPECT_TRUE(parsed_config->retryable_status_codes().Empty());
1389 }
1390 
1391 TEST_F(RetryParserTest, InvalidRetryPolicyPerAttemptRecvTimeoutUnparseable) {
1392  const char* test_json =
1393  "{\n"
1394  " \"methodConfig\": [ {\n"
1395  " \"name\": [\n"
1396  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1397  " ],\n"
1398  " \"retryPolicy\": {\n"
1399  " \"maxAttempts\": 2,\n"
1400  " \"initialBackoff\": \"1s\",\n"
1401  " \"maxBackoff\": \"120s\",\n"
1402  " \"backoffMultiplier\": \"1.6\",\n"
1403  " \"perAttemptRecvTimeout\": \"1sec\",\n"
1404  " \"retryableStatusCodes\": [\"ABORTED\"]\n"
1405  " }\n"
1406  " } ]\n"
1407  "}";
1410  const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1);
1411  grpc_channel_args args = {1, &arg};
1412  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
1415  "Service config parsing error" CHILD_ERROR_TAG
1416  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1417  "retryPolicy" CHILD_ERROR_TAG
1418  "field:perAttemptRecvTimeout error:type must be STRING "
1419  "of the form given by google.proto.Duration."));
1421 }
1422 
1423 TEST_F(RetryParserTest, InvalidRetryPolicyPerAttemptRecvTimeoutWrongType) {
1424  const char* test_json =
1425  "{\n"
1426  " \"methodConfig\": [ {\n"
1427  " \"name\": [\n"
1428  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1429  " ],\n"
1430  " \"retryPolicy\": {\n"
1431  " \"maxAttempts\": 2,\n"
1432  " \"initialBackoff\": \"1s\",\n"
1433  " \"maxBackoff\": \"120s\",\n"
1434  " \"backoffMultiplier\": \"1.6\",\n"
1435  " \"perAttemptRecvTimeout\": 1,\n"
1436  " \"retryableStatusCodes\": [\"ABORTED\"]\n"
1437  " }\n"
1438  " } ]\n"
1439  "}";
1442  const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1);
1443  grpc_channel_args args = {1, &arg};
1444  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
1447  "Service config parsing error" CHILD_ERROR_TAG
1448  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1449  "retryPolicy" CHILD_ERROR_TAG
1450  "field:perAttemptRecvTimeout error:type must be STRING "
1451  "of the form given by google.proto.Duration."));
1453 }
1454 
1455 TEST_F(RetryParserTest, InvalidRetryPolicyPerAttemptRecvTimeoutBadValue) {
1456  const char* test_json =
1457  "{\n"
1458  " \"methodConfig\": [ {\n"
1459  " \"name\": [\n"
1460  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1461  " ],\n"
1462  " \"retryPolicy\": {\n"
1463  " \"maxAttempts\": 2,\n"
1464  " \"initialBackoff\": \"1s\",\n"
1465  " \"maxBackoff\": \"120s\",\n"
1466  " \"backoffMultiplier\": \"1.6\",\n"
1467  " \"perAttemptRecvTimeout\": \"0s\",\n"
1468  " \"retryableStatusCodes\": [\"ABORTED\"]\n"
1469  " }\n"
1470  " } ]\n"
1471  "}";
1474  const_cast<char*>(GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING), 1);
1475  grpc_channel_args args = {1, &arg};
1476  auto svc_cfg = ServiceConfigImpl::Create(&args, test_json, &error);
1479  "Service config parsing error" CHILD_ERROR_TAG
1480  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1481  "retryPolicy" CHILD_ERROR_TAG
1482  "field:perAttemptRecvTimeout error:must be greater than 0"));
1484 }
1485 
1486 //
1487 // message_size parser tests
1488 //
1489 
1491  protected:
1492  void SetUp() override {
1496  builder->service_config_parser()->RegisterParser(
1497  absl::make_unique<MessageSizeParser>());
1498  });
1499  EXPECT_EQ(CoreConfiguration::Get().service_config_parser().GetParserIndex(
1500  "message_size"),
1501  0);
1502  }
1503 };
1504 
1506  const char* test_json =
1507  "{\n"
1508  " \"methodConfig\": [ {\n"
1509  " \"name\": [\n"
1510  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1511  " ],\n"
1512  " \"maxRequestMessageBytes\": 1024,\n"
1513  " \"maxResponseMessageBytes\": 1024\n"
1514  " } ]\n"
1515  "}";
1517  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1519  const auto* vector_ptr = svc_cfg->GetMethodParsedConfigVector(
1520  grpc_slice_from_static_string("/TestServ/TestMethod"));
1521  ASSERT_NE(vector_ptr, nullptr);
1522  auto parsed_config =
1523  static_cast<MessageSizeParsedConfig*>(((*vector_ptr)[0]).get());
1524  ASSERT_NE(parsed_config, nullptr);
1525  EXPECT_EQ(parsed_config->limits().max_send_size, 1024);
1526  EXPECT_EQ(parsed_config->limits().max_recv_size, 1024);
1527 }
1528 
1529 TEST_F(MessageSizeParserTest, InvalidMaxRequestMessageBytes) {
1530  const char* test_json =
1531  "{\n"
1532  " \"methodConfig\": [ {\n"
1533  " \"name\": [\n"
1534  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1535  " ],\n"
1536  " \"maxRequestMessageBytes\": -1024\n"
1537  " } ]\n"
1538  "}";
1540  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1543  "Service config parsing error" CHILD_ERROR_TAG
1544  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1545  "Message size parser" CHILD_ERROR_TAG
1546  "field:maxRequestMessageBytes error:should be non-negative"));
1548 }
1549 
1550 TEST_F(MessageSizeParserTest, InvalidMaxResponseMessageBytes) {
1551  const char* test_json =
1552  "{\n"
1553  " \"methodConfig\": [ {\n"
1554  " \"name\": [\n"
1555  " { \"service\": \"TestServ\", \"method\": \"TestMethod\" }\n"
1556  " ],\n"
1557  " \"maxResponseMessageBytes\": {}\n"
1558  " } ]\n"
1559  "}";
1561  auto svc_cfg = ServiceConfigImpl::Create(nullptr, test_json, &error);
1564  "Service config parsing error" CHILD_ERROR_TAG
1565  "Method Params" CHILD_ERROR_TAG "methodConfig" CHILD_ERROR_TAG
1566  "Message size parser" CHILD_ERROR_TAG
1567  "field:maxResponseMessageBytes error:should be of type "
1568  "number"));
1570 }
1571 
1572 } // namespace testing
1573 } // namespace grpc_core
1574 
1575 int main(int argc, char** argv) {
1576  ::testing::InitGoogleTest(&argc, argv);
1577  grpc::testing::TestEnvironment env(&argc, argv);
1578  grpc_init();
1579  int ret = RUN_ALL_TESTS();
1580  grpc_shutdown();
1581  return ret;
1582 }
grpc_core::testing::ErrorParser
Definition: service_config_test.cc:142
grpc_arg
Definition: grpc_types.h:103
grpc_core::MessageSizeParsedConfig
Definition: message_size_filter.h:43
testing
Definition: aws_request_signer_test.cc:25
ASSERT_NE
#define ASSERT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2060
testing::ContainsRegex
PolymorphicMatcher< internal::MatchesRegexMatcher > ContainsRegex(const internal::RE *regex)
Definition: cares/cares/test/gmock-1.8.0/gmock/gmock.h:8835
regen-readme.it
it
Definition: regen-readme.py:15
GRPC_ERROR_NONE
#define GRPC_ERROR_NONE
Definition: error.h:234
port.h
grpc_core::testing::TestParser2::InvalidValueErrorMessage
static const char * InvalidValueErrorMessage()
Definition: service_config_test.cc:136
get
absl::string_view get(const Cont &c)
Definition: abseil-cpp/absl/strings/str_replace_test.cc:185
grpc_core::testing::TestParser2
Definition: service_config_test.cc:103
generate.env
env
Definition: generate.py:37
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
GPR_DEBUG_ASSERT
#define GPR_DEBUG_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:103
grpc_core::testing::TestParser2::ParsePerMethodParams
std::unique_ptr< ServiceConfigParser::ParsedConfig > ParsePerMethodParams(const grpc_channel_args *args, const Json &json, grpc_error_handle *error) override
Definition: service_config_test.cc:107
grpc_core::internal::RetryGlobalConfig
Definition: retry_service_config.h:42
EXPECT_THAT
#define EXPECT_THAT(value, matcher)
grpc_core
Definition: call_metric_recorder.h:31
grpc_core::CoreConfiguration::Builder
Definition: core_configuration.h:41
grpc_core::ServiceConfigParser::Parser
This is the base class that all service config parsers should derive from.
Definition: lib/service_config/service_config_parser.h:51
grpc_core::testing::TestParsedConfig1::value
int value() const
Definition: service_config_test.cc:59
string.h
absl::string_view
Definition: abseil-cpp/absl/strings/string_view.h:167
grpc_core::internal::ClientChannelGlobalParsedConfig::parsed_lb_config
RefCountedPtr< LoadBalancingPolicy::Config > parsed_lb_config() const
Definition: resolver_result_parsing.h:55
error
grpc_error_handle error
Definition: retry_filter.cc:499
grpc_core::testing::TestParser1::name
absl::string_view name() const override
Definition: service_config_test.cc:67
grpc_core::testing::TestParsedConfig1::value_
int value_
Definition: service_config_test.cc:62
grpc_core::Json::object_value
const Object & object_value() const
Definition: src/core/lib/json/json.h:177
grpc_core::testing::TestParser1::ParseGlobalParams
std::unique_ptr< ServiceConfigParser::ParsedConfig > ParseGlobalParams(const grpc_channel_args *args, const Json &json, grpc_error_handle *error) override
Definition: service_config_test.cc:69
grpc_core::testing::TestParser1::InvalidValueErrorMessage
static const char * InvalidValueErrorMessage()
Definition: service_config_test.cc:98
grpc_core::testing::TEST_F
TEST_F(ServiceConfigTest, ErrorCheck1)
Definition: service_config_test.cc:192
grpc_core::testing::ErrorParser::name
absl::string_view name() const override
Definition: service_config_test.cc:146
grpc_core::testing::ErrorParser::ErrorParser
ErrorParser(absl::string_view name)
Definition: service_config_test.cc:144
grpc_core::internal::RetryMethodConfig
Definition: retry_service_config.h:56
grpc_channel_args_find_bool
bool grpc_channel_args_find_bool(const grpc_channel_args *args, const char *name, bool default_value)
Definition: channel_args.cc:465
grpc_channel_args
Definition: grpc_types.h:132
testing::Test
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:402
grpc_core::testing::ErrorParser::ParsePerMethodParams
std::unique_ptr< ServiceConfigParser::ParsedConfig > ParsePerMethodParams(const grpc_channel_args *, const Json &, grpc_error_handle *error) override
Definition: service_config_test.cc:148
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
grpc_core::CoreConfiguration::BuildSpecialConfiguration
static void BuildSpecialConfiguration(BuildFunc build)
Definition: core_configuration.h:100
grpc_core::testing::ErroredParsersScopingTest::SetUp
void SetUp() override
Definition: service_config_test.cc:464
profile_analyzer.builder
builder
Definition: profile_analyzer.py:159
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
grpc_core::CoreConfiguration::Get
static const CoreConfiguration & Get()
Definition: core_configuration.h:82
GRPC_ARG_DISABLE_PARSING
#define GRPC_ARG_DISABLE_PARSING
Definition: service_config_test.cc:46
Json
JSON (JavaScript Object Notation).
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:227
ASSERT_DEATH_IF_SUPPORTED
#define ASSERT_DEATH_IF_SUPPORTED(statement, regex)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-death-test.h:337
grpc_core::testing::ErrorParser::name_
absl::string_view name_
Definition: service_config_test.cc:169
grpc_core::testing::ServiceConfigTest
Definition: service_config_test.cc:172
GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING
#define GRPC_ARG_EXPERIMENTAL_ENABLE_HEDGING
Definition: grpc_types.h:405
grpc.h
retry_service_config.h
arg
Definition: cmdline.cc:40
grpc_slice_from_static_string
GPRAPI grpc_slice grpc_slice_from_static_string(const char *source)
Definition: slice/slice.cc:89
time.h
grpc_core::Json::Type::NUMBER
@ NUMBER
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
grpc_core::ServiceConfigImpl::Create
static RefCountedPtr< ServiceConfig > Create(const grpc_channel_args *args, absl::string_view json_string, grpc_error_handle *error)
Definition: service_config_impl.cc:41
message_size_filter.h
grpc_core::testing::ErrorParser::GlobalError
static const char * GlobalError()
Definition: service_config_test.cc:166
GRPC_ERROR_CREATE_FROM_STATIC_STRING
#define GRPC_ERROR_CREATE_FROM_STATIC_STRING(desc)
Definition: error.h:291
service_config_parser.h
grpc_core::testing::MessageSizeParserTest
Definition: service_config_test.cc:1490
grpc_core::testing::TestParser1::InvalidTypeErrorMessage
static const char * InvalidTypeErrorMessage()
Definition: service_config_test.cc:94
test_config.h
value
const char * value
Definition: hpack_parser_table.cc:165
EXPECT_STREQ
#define EXPECT_STREQ(s1, s2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2095
wait_for_ready
bool wait_for_ready
Definition: rls_end2end_test.cc:240
grpc_core::testing::TestParser2::InvalidTypeErrorMessage
static const char * InvalidTypeErrorMessage()
Definition: service_config_test.cc:132
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
grpc_core::testing::TestParsedConfig1::TestParsedConfig1
TestParsedConfig1(int value)
Definition: service_config_test.cc:57
grpc_core::testing::TestParsedConfig1
Definition: service_config_test.cc:55
grpc_channel_arg_integer_create
grpc_arg grpc_channel_arg_integer_create(char *name, int value)
Definition: channel_args.cc:484
grpc_core::testing::ErrorParser::MethodError
static const char * MethodError()
Definition: service_config_test.cc:164
grpc_error_std_string
std::string grpc_error_std_string(grpc_error_handle error)
Definition: error.cc:944
grpc_core::testing::ClientChannelParserTest
Definition: service_config_test.cc:514
GRPC_STATUS_ABORTED
@ GRPC_STATUS_ABORTED
Definition: include/grpc/impl/codegen/status.h:104
grpc_core::testing::RetryParserTest
Definition: service_config_test.cc:808
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
grpc::testing::TestEnvironment
Definition: test/core/util/test_config.h:54
service_config_impl.h
grpc_core::Duration::Seconds
static constexpr Duration Seconds(int64_t seconds)
Definition: src/core/lib/gprpp/time.h:151
grpc_core::testing::TestParser2::name
absl::string_view name() const override
Definition: service_config_test.cc:105
grpc_core::CoreConfiguration::Reset
static void Reset()
Definition: core_configuration.cc:96
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
grpc_core::testing::ClientChannelParserTest::SetUp
void SetUp() override
Definition: service_config_test.cc:516
main
int main(int argc, char **argv)
Definition: service_config_test.cc:1575
GRPC_ERROR_UNREF
#define GRPC_ERROR_UNREF(err)
Definition: error.h:262
grpc_core::testing::ErrorParser::ParseGlobalParams
std::unique_ptr< ServiceConfigParser::ParsedConfig > ParseGlobalParams(const grpc_channel_args *, const Json &, grpc_error_handle *error) override
Definition: service_config_test.cc:156
grpc_core::testing::TEST
TEST(ServiceConfigParserTest, DoubleRegistration)
Definition: service_config_test.cc:448
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
gpr_parse_nonnegative_int
int gpr_parse_nonnegative_int(const char *value)
Definition: string.cc:218
CHILD_ERROR_TAG
#define CHILD_ERROR_TAG
Definition: service_config_test.cc:52
service_config.h
grpc_core::testing::TestParser1
Definition: service_config_test.cc:65
grpc_core::internal::ClientChannelMethodParsedConfig
Definition: resolver_result_parsing.h:73
grpc_init
GRPCAPI void grpc_init(void)
Definition: init.cc:146
grpc_error
Definition: error_internal.h:42
resolver_result_parsing.h
grpc_core::testing::RetryParserTest::SetUp
void SetUp() override
Definition: service_config_test.cc:810
grpc_core::internal::ClientChannelGlobalParsedConfig
Definition: resolver_result_parsing.h:44
grpc_shutdown
GRPCAPI void grpc_shutdown(void)
Definition: init.cc:209
grpc_core::ServiceConfigParser::ParsedConfig
Definition: lib/service_config/service_config_parser.h:45
grpc_core::testing::ServiceConfigTest::SetUp
void SetUp() override
Definition: service_config_test.cc:174
timeout
uv_timer_t timeout
Definition: libuv/docs/code/uvwget/main.c:9
grpc_core::testing::MessageSizeParserTest::SetUp
void SetUp() override
Definition: service_config_test.cc:1492
ASSERT_EQ
#define ASSERT_EQ(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2056
grpc_core::testing::ErroredParsersScopingTest
Definition: service_config_test.cc:462
grpc_core::Duration::Minutes
static constexpr Duration Minutes(int64_t minutes)
Definition: src/core/lib/gprpp/time.h:147


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:12