xds_bootstrap_test.cc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  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. #include <regex>
  17. #include "absl/strings/numbers.h"
  18. #include "absl/strings/str_format.h"
  19. #include <gmock/gmock.h>
  20. #include <gtest/gtest.h>
  21. #include <grpc/grpc.h>
  22. #include <grpc/slice.h>
  23. #include "src/core/ext/xds/certificate_provider_registry.h"
  24. #include "src/core/ext/xds/xds_bootstrap.h"
  25. #include "src/core/lib/gpr/env.h"
  26. #include "src/core/lib/gpr/tmpfile.h"
  27. #include "test/core/util/test_config.h"
  28. namespace grpc_core {
  29. namespace testing {
  30. class TestType {
  31. public:
  32. explicit TestType(bool parse_xds_certificate_providers)
  33. : parse_xds_certificate_providers_(parse_xds_certificate_providers) {}
  34. bool parse_xds_certificate_providers() const {
  35. return parse_xds_certificate_providers_;
  36. }
  37. std::string AsString() const {
  38. return parse_xds_certificate_providers_
  39. ? "WithCertificateProvidersParsing"
  40. : "WithoutCertificateProvidersParsing";
  41. }
  42. private:
  43. const bool parse_xds_certificate_providers_;
  44. };
  45. class XdsBootstrapTest : public ::testing::TestWithParam<TestType> {
  46. public:
  47. XdsBootstrapTest() {
  48. if (GetParam().parse_xds_certificate_providers()) {
  49. gpr_setenv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT", "true");
  50. } else {
  51. gpr_unsetenv("GRPC_XDS_EXPERIMENTAL_SECURITY_SUPPORT");
  52. }
  53. grpc_init();
  54. }
  55. ~XdsBootstrapTest() override { grpc_shutdown_blocking(); }
  56. };
  57. TEST_P(XdsBootstrapTest, Basic) {
  58. const char* json_str =
  59. "{"
  60. " \"xds_servers\": ["
  61. " {"
  62. " \"server_uri\": \"fake:///lb\","
  63. " \"channel_creds\": ["
  64. " {"
  65. " \"type\": \"fake\","
  66. " \"ignore\": 0"
  67. " }"
  68. " ],"
  69. " \"ignore\": 0"
  70. " },"
  71. " {"
  72. " \"server_uri\": \"ignored\","
  73. " \"channel_creds\": ["
  74. " {"
  75. " \"type\": \"ignored\","
  76. " \"ignore\": 0"
  77. " },"
  78. " {"
  79. " \"type\": \"fake\""
  80. " }"
  81. " ],"
  82. " \"ignore\": 0"
  83. " }"
  84. " ],"
  85. " \"node\": {"
  86. " \"id\": \"foo\","
  87. " \"cluster\": \"bar\","
  88. " \"locality\": {"
  89. " \"region\": \"milky_way\","
  90. " \"zone\": \"sol_system\","
  91. " \"sub_zone\": \"earth\","
  92. " \"ignore\": {}"
  93. " },"
  94. " \"metadata\": {"
  95. " \"foo\": 1,"
  96. " \"bar\": 2"
  97. " },"
  98. " \"ignore\": \"whee\""
  99. " },"
  100. " \"server_listener_resource_name_template\": \"example/resource\","
  101. " \"ignore\": {}"
  102. "}";
  103. grpc_error* error = GRPC_ERROR_NONE;
  104. Json json = Json::Parse(json_str, &error);
  105. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  106. XdsBootstrap bootstrap(std::move(json), &error);
  107. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  108. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  109. EXPECT_EQ(bootstrap.server().channel_creds_type, "fake");
  110. EXPECT_EQ(bootstrap.server().channel_creds_config.type(),
  111. Json::Type::JSON_NULL);
  112. ASSERT_NE(bootstrap.node(), nullptr);
  113. EXPECT_EQ(bootstrap.node()->id, "foo");
  114. EXPECT_EQ(bootstrap.node()->cluster, "bar");
  115. EXPECT_EQ(bootstrap.node()->locality_region, "milky_way");
  116. EXPECT_EQ(bootstrap.node()->locality_zone, "sol_system");
  117. EXPECT_EQ(bootstrap.node()->locality_sub_zone, "earth");
  118. ASSERT_EQ(bootstrap.node()->metadata.type(), Json::Type::OBJECT);
  119. EXPECT_THAT(bootstrap.node()->metadata.object_value(),
  120. ::testing::ElementsAre(
  121. ::testing::Pair(
  122. ::testing::Eq("bar"),
  123. ::testing::AllOf(
  124. ::testing::Property(&Json::type, Json::Type::NUMBER),
  125. ::testing::Property(&Json::string_value, "2"))),
  126. ::testing::Pair(
  127. ::testing::Eq("foo"),
  128. ::testing::AllOf(
  129. ::testing::Property(&Json::type, Json::Type::NUMBER),
  130. ::testing::Property(&Json::string_value, "1")))));
  131. EXPECT_EQ(bootstrap.server_listener_resource_name_template(),
  132. "example/resource");
  133. }
  134. TEST_P(XdsBootstrapTest, ValidWithoutNode) {
  135. const char* json_str =
  136. "{"
  137. " \"xds_servers\": ["
  138. " {"
  139. " \"server_uri\": \"fake:///lb\","
  140. " \"channel_creds\": [{\"type\": \"fake\"}]"
  141. " }"
  142. " ]"
  143. "}";
  144. grpc_error* error = GRPC_ERROR_NONE;
  145. Json json = Json::Parse(json_str, &error);
  146. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  147. XdsBootstrap bootstrap(std::move(json), &error);
  148. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  149. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  150. EXPECT_EQ(bootstrap.server().channel_creds_type, "fake");
  151. EXPECT_EQ(bootstrap.node(), nullptr);
  152. }
  153. TEST_P(XdsBootstrapTest, InsecureCreds) {
  154. const char* json_str =
  155. "{"
  156. " \"xds_servers\": ["
  157. " {"
  158. " \"server_uri\": \"fake:///lb\","
  159. " \"channel_creds\": [{\"type\": \"insecure\"}]"
  160. " }"
  161. " ]"
  162. "}";
  163. grpc_error* error = GRPC_ERROR_NONE;
  164. Json json = Json::Parse(json_str, &error);
  165. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  166. XdsBootstrap bootstrap(std::move(json), &error);
  167. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  168. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  169. EXPECT_EQ(bootstrap.server().channel_creds_type, "insecure");
  170. EXPECT_EQ(bootstrap.node(), nullptr);
  171. }
  172. TEST_P(XdsBootstrapTest, GoogleDefaultCreds) {
  173. // Generate call creds file needed by GoogleDefaultCreds.
  174. const char token_str[] =
  175. "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
  176. " \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
  177. " \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
  178. " \"type\": \"authorized_user\"}";
  179. char* creds_file_name;
  180. FILE* creds_file = gpr_tmpfile("xds_bootstrap_test", &creds_file_name);
  181. ASSERT_NE(creds_file_name, nullptr);
  182. ASSERT_NE(creds_file, nullptr);
  183. ASSERT_EQ(fwrite(token_str, 1, sizeof(token_str), creds_file),
  184. sizeof(token_str));
  185. fclose(creds_file);
  186. gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
  187. gpr_free(creds_file_name);
  188. // Now run test.
  189. const char* json_str =
  190. "{"
  191. " \"xds_servers\": ["
  192. " {"
  193. " \"server_uri\": \"fake:///lb\","
  194. " \"channel_creds\": [{\"type\": \"google_default\"}]"
  195. " }"
  196. " ]"
  197. "}";
  198. grpc_error* error = GRPC_ERROR_NONE;
  199. Json json = Json::Parse(json_str, &error);
  200. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  201. XdsBootstrap bootstrap(std::move(json), &error);
  202. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  203. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  204. EXPECT_EQ(bootstrap.server().channel_creds_type, "google_default");
  205. EXPECT_EQ(bootstrap.node(), nullptr);
  206. }
  207. TEST_P(XdsBootstrapTest, MissingChannelCreds) {
  208. const char* json_str =
  209. "{"
  210. " \"xds_servers\": ["
  211. " {"
  212. " \"server_uri\": \"fake:///lb\""
  213. " }"
  214. " ]"
  215. "}";
  216. grpc_error* error = GRPC_ERROR_NONE;
  217. Json json = Json::Parse(json_str, &error);
  218. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  219. XdsBootstrap bootstrap(std::move(json), &error);
  220. EXPECT_THAT(grpc_error_string(error),
  221. ::testing::ContainsRegex("\"channel_creds\" field not present"));
  222. GRPC_ERROR_UNREF(error);
  223. }
  224. TEST_P(XdsBootstrapTest, NoKnownChannelCreds) {
  225. const char* json_str =
  226. "{"
  227. " \"xds_servers\": ["
  228. " {"
  229. " \"server_uri\": \"fake:///lb\","
  230. " \"channel_creds\": [{\"type\": \"unknown\"}]"
  231. " }"
  232. " ]"
  233. "}";
  234. grpc_error* error = GRPC_ERROR_NONE;
  235. Json json = Json::Parse(json_str, &error);
  236. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  237. XdsBootstrap bootstrap(std::move(json), &error);
  238. EXPECT_THAT(grpc_error_string(error),
  239. ::testing::ContainsRegex(
  240. "no known creds type found in \"channel_creds\""));
  241. GRPC_ERROR_UNREF(error);
  242. }
  243. TEST_P(XdsBootstrapTest, MissingXdsServers) {
  244. grpc_error* error = GRPC_ERROR_NONE;
  245. Json json = Json::Parse("{}", &error);
  246. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  247. XdsBootstrap bootstrap(std::move(json), &error);
  248. EXPECT_THAT(grpc_error_string(error),
  249. ::testing::ContainsRegex("\"xds_servers\" field not present"));
  250. GRPC_ERROR_UNREF(error);
  251. }
  252. TEST_P(XdsBootstrapTest, TopFieldsWrongTypes) {
  253. const char* json_str =
  254. "{"
  255. " \"xds_servers\":1,"
  256. " \"node\":1,"
  257. " \"server_listener_resource_name_template\":1,"
  258. " \"certificate_providers\":1"
  259. "}";
  260. grpc_error* error = GRPC_ERROR_NONE;
  261. Json json = Json::Parse(json_str, &error);
  262. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  263. XdsBootstrap bootstrap(std::move(json), &error);
  264. EXPECT_THAT(grpc_error_string(error),
  265. ::testing::ContainsRegex("\"xds_servers\" field is not an array.*"
  266. "\"node\" field is not an object.*"
  267. "\"server_listener_resource_name_"
  268. "template\" field is not a string.*"));
  269. if (GetParam().parse_xds_certificate_providers()) {
  270. EXPECT_THAT(grpc_error_string(error),
  271. ::testing::ContainsRegex(
  272. "\"certificate_providers\" field is not an object"));
  273. }
  274. GRPC_ERROR_UNREF(error);
  275. }
  276. TEST_P(XdsBootstrapTest, XdsServerMissingServerUri) {
  277. const char* json_str =
  278. "{"
  279. " \"xds_servers\":[{}]"
  280. "}";
  281. grpc_error* error = GRPC_ERROR_NONE;
  282. Json json = Json::Parse(json_str, &error);
  283. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  284. XdsBootstrap bootstrap(std::move(json), &error);
  285. EXPECT_THAT(grpc_error_string(error),
  286. ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
  287. "errors parsing index 0.*"
  288. "\"server_uri\" field not present"));
  289. GRPC_ERROR_UNREF(error);
  290. }
  291. TEST_P(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
  292. const char* json_str =
  293. "{"
  294. " \"xds_servers\":["
  295. " {"
  296. " \"server_uri\":1,"
  297. " \"channel_creds\":1"
  298. " }"
  299. " ]"
  300. "}";
  301. grpc_error* error = GRPC_ERROR_NONE;
  302. Json json = Json::Parse(json_str, &error);
  303. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  304. XdsBootstrap bootstrap(std::move(json), &error);
  305. EXPECT_THAT(
  306. grpc_error_string(error),
  307. ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
  308. "errors parsing index 0.*"
  309. "\"server_uri\" field is not a string.*"
  310. "\"channel_creds\" field is not an array"));
  311. GRPC_ERROR_UNREF(error);
  312. }
  313. TEST_P(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
  314. const char* json_str =
  315. "{"
  316. " \"xds_servers\":["
  317. " {"
  318. " \"server_uri\":\"foo\","
  319. " \"channel_creds\":["
  320. " {"
  321. " \"type\":0,"
  322. " \"config\":1"
  323. " }"
  324. " ]"
  325. " }"
  326. " ]"
  327. "}";
  328. grpc_error* error = GRPC_ERROR_NONE;
  329. Json json = Json::Parse(json_str, &error);
  330. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  331. XdsBootstrap bootstrap(std::move(json), &error);
  332. EXPECT_THAT(
  333. grpc_error_string(error),
  334. ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
  335. "errors parsing index 0.*"
  336. "errors parsing \"channel_creds\" array.*"
  337. "errors parsing index 0.*"
  338. "\"type\" field is not a string.*"
  339. "\"config\" field is not an object"));
  340. GRPC_ERROR_UNREF(error);
  341. }
  342. TEST_P(XdsBootstrapTest, NodeFieldsWrongTypes) {
  343. const char* json_str =
  344. "{"
  345. " \"node\":{"
  346. " \"id\":0,"
  347. " \"cluster\":0,"
  348. " \"locality\":0,"
  349. " \"metadata\":0"
  350. " }"
  351. "}";
  352. grpc_error* error = GRPC_ERROR_NONE;
  353. Json json = Json::Parse(json_str, &error);
  354. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  355. XdsBootstrap bootstrap(std::move(json), &error);
  356. EXPECT_THAT(grpc_error_string(error),
  357. ::testing::ContainsRegex("errors parsing \"node\" object.*"
  358. "\"id\" field is not a string.*"
  359. "\"cluster\" field is not a string.*"
  360. "\"locality\" field is not an object.*"
  361. "\"metadata\" field is not an object"));
  362. GRPC_ERROR_UNREF(error);
  363. }
  364. TEST_P(XdsBootstrapTest, LocalityFieldsWrongType) {
  365. const char* json_str =
  366. "{"
  367. " \"node\":{"
  368. " \"locality\":{"
  369. " \"region\":0,"
  370. " \"zone\":0,"
  371. " \"sub_zone\":0"
  372. " }"
  373. " }"
  374. "}";
  375. grpc_error* error = GRPC_ERROR_NONE;
  376. Json json = Json::Parse(json_str, &error);
  377. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  378. XdsBootstrap bootstrap(std::move(json), &error);
  379. EXPECT_THAT(grpc_error_string(error),
  380. ::testing::ContainsRegex("errors parsing \"node\" object.*"
  381. "errors parsing \"locality\" object.*"
  382. "\"region\" field is not a string.*"
  383. "\"zone\" field is not a string.*"
  384. "\"sub_zone\" field is not a string"));
  385. GRPC_ERROR_UNREF(error);
  386. }
  387. TEST_P(XdsBootstrapTest, CertificateProvidersElementWrongType) {
  388. const char* json_str =
  389. "{"
  390. " \"xds_servers\": ["
  391. " {"
  392. " \"server_uri\": \"fake:///lb\","
  393. " \"channel_creds\": [{\"type\": \"fake\"}]"
  394. " }"
  395. " ],"
  396. " \"certificate_providers\": {"
  397. " \"plugin\":1"
  398. " }"
  399. "}";
  400. grpc_error* error = GRPC_ERROR_NONE;
  401. Json json = Json::Parse(json_str, &error);
  402. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  403. XdsBootstrap bootstrap(std::move(json), &error);
  404. if (GetParam().parse_xds_certificate_providers()) {
  405. EXPECT_THAT(grpc_error_string(error),
  406. ::testing::ContainsRegex(
  407. "errors parsing \"certificate_providers\" object.*"
  408. "element \"plugin\" is not an object"));
  409. } else {
  410. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  411. }
  412. GRPC_ERROR_UNREF(error);
  413. }
  414. TEST_P(XdsBootstrapTest, CertificateProvidersPluginNameWrongType) {
  415. const char* json_str =
  416. "{"
  417. " \"xds_servers\": ["
  418. " {"
  419. " \"server_uri\": \"fake:///lb\","
  420. " \"channel_creds\": [{\"type\": \"fake\"}]"
  421. " }"
  422. " ],"
  423. " \"certificate_providers\": {"
  424. " \"plugin\": {"
  425. " \"plugin_name\":1"
  426. " }"
  427. " }"
  428. "}";
  429. grpc_error* error = GRPC_ERROR_NONE;
  430. Json json = Json::Parse(json_str, &error);
  431. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  432. XdsBootstrap bootstrap(std::move(json), &error);
  433. if (GetParam().parse_xds_certificate_providers()) {
  434. EXPECT_THAT(grpc_error_string(error),
  435. ::testing::ContainsRegex(
  436. "errors parsing \"certificate_providers\" object.*"
  437. "errors parsing element \"plugin\".*"
  438. "\"plugin_name\" field is not a string"));
  439. } else {
  440. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  441. }
  442. GRPC_ERROR_UNREF(error);
  443. }
  444. class FakeCertificateProviderFactory : public CertificateProviderFactory {
  445. public:
  446. class Config : public CertificateProviderFactory::Config {
  447. public:
  448. explicit Config(int value) : value_(value) {}
  449. int value() const { return value_; }
  450. const char* name() const override { return "fake"; }
  451. std::string ToString() const override {
  452. return absl::StrFormat(
  453. "{\n"
  454. " value=%d"
  455. "}",
  456. value_);
  457. }
  458. private:
  459. int value_;
  460. };
  461. const char* name() const override { return "fake"; }
  462. RefCountedPtr<CertificateProviderFactory::Config>
  463. CreateCertificateProviderConfig(const Json& config_json,
  464. grpc_error** error) override {
  465. std::vector<grpc_error*> error_list;
  466. EXPECT_EQ(config_json.type(), Json::Type::OBJECT);
  467. auto it = config_json.object_value().find("value");
  468. if (it == config_json.object_value().end()) {
  469. return MakeRefCounted<FakeCertificateProviderFactory::Config>(0);
  470. } else if (it->second.type() != Json::Type::NUMBER) {
  471. *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
  472. "field:config field:value not of type number");
  473. } else {
  474. int value = 0;
  475. EXPECT_TRUE(absl::SimpleAtoi(it->second.string_value(), &value));
  476. return MakeRefCounted<FakeCertificateProviderFactory::Config>(value);
  477. }
  478. return nullptr;
  479. }
  480. RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
  481. RefCountedPtr<CertificateProviderFactory::Config> /*config*/) override {
  482. return nullptr;
  483. }
  484. };
  485. TEST_P(XdsBootstrapTest, CertificateProvidersFakePluginParsingError) {
  486. CertificateProviderRegistry::RegisterCertificateProviderFactory(
  487. absl::make_unique<FakeCertificateProviderFactory>());
  488. const char* json_str =
  489. "{"
  490. " \"xds_servers\": ["
  491. " {"
  492. " \"server_uri\": \"fake:///lb\","
  493. " \"channel_creds\": [{\"type\": \"fake\"}]"
  494. " }"
  495. " ],"
  496. " \"certificate_providers\": {"
  497. " \"fake_plugin\": {"
  498. " \"plugin_name\": \"fake\","
  499. " \"config\": {"
  500. " \"value\": \"10\""
  501. " }"
  502. " }"
  503. " }"
  504. "}";
  505. grpc_error* error = GRPC_ERROR_NONE;
  506. Json json = Json::Parse(json_str, &error);
  507. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  508. XdsBootstrap bootstrap(std::move(json), &error);
  509. if (GetParam().parse_xds_certificate_providers()) {
  510. EXPECT_THAT(grpc_error_string(error),
  511. ::testing::ContainsRegex(
  512. "errors parsing \"certificate_providers\" object.*"
  513. "errors parsing element \"fake_plugin\".*"
  514. "field:config field:value not of type number"));
  515. } else {
  516. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  517. }
  518. GRPC_ERROR_UNREF(error);
  519. }
  520. TEST_P(XdsBootstrapTest, CertificateProvidersFakePluginParsingSuccess) {
  521. CertificateProviderRegistry::RegisterCertificateProviderFactory(
  522. absl::make_unique<FakeCertificateProviderFactory>());
  523. const char* json_str =
  524. "{"
  525. " \"xds_servers\": ["
  526. " {"
  527. " \"server_uri\": \"fake:///lb\","
  528. " \"channel_creds\": [{\"type\": \"fake\"}]"
  529. " }"
  530. " ],"
  531. " \"certificate_providers\": {"
  532. " \"fake_plugin\": {"
  533. " \"plugin_name\": \"fake\","
  534. " \"config\": {"
  535. " \"value\": 10"
  536. " }"
  537. " }"
  538. " }"
  539. "}";
  540. grpc_error* error = GRPC_ERROR_NONE;
  541. Json json = Json::Parse(json_str, &error);
  542. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  543. XdsBootstrap bootstrap(std::move(json), &error);
  544. ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_string(error);
  545. if (GetParam().parse_xds_certificate_providers()) {
  546. const CertificateProviderStore::PluginDefinition& fake_plugin =
  547. bootstrap.certificate_providers().at("fake_plugin");
  548. ASSERT_EQ(fake_plugin.plugin_name, "fake");
  549. ASSERT_STREQ(fake_plugin.config->name(), "fake");
  550. ASSERT_EQ(
  551. static_cast<RefCountedPtr<FakeCertificateProviderFactory::Config>>(
  552. fake_plugin.config)
  553. ->value(),
  554. 10);
  555. } else {
  556. EXPECT_TRUE(bootstrap.certificate_providers().empty());
  557. }
  558. }
  559. TEST_P(XdsBootstrapTest, CertificateProvidersFakePluginEmptyConfig) {
  560. CertificateProviderRegistry::RegisterCertificateProviderFactory(
  561. absl::make_unique<FakeCertificateProviderFactory>());
  562. const char* json_str =
  563. "{"
  564. " \"xds_servers\": ["
  565. " {"
  566. " \"server_uri\": \"fake:///lb\","
  567. " \"channel_creds\": [{\"type\": \"fake\"}]"
  568. " }"
  569. " ],"
  570. " \"certificate_providers\": {"
  571. " \"fake_plugin\": {"
  572. " \"plugin_name\": \"fake\""
  573. " }"
  574. " }"
  575. "}";
  576. grpc_error* error = GRPC_ERROR_NONE;
  577. Json json = Json::Parse(json_str, &error);
  578. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_string(error);
  579. XdsBootstrap bootstrap(std::move(json), &error);
  580. ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_string(error);
  581. if (GetParam().parse_xds_certificate_providers()) {
  582. const CertificateProviderStore::PluginDefinition& fake_plugin =
  583. bootstrap.certificate_providers().at("fake_plugin");
  584. ASSERT_EQ(fake_plugin.plugin_name, "fake");
  585. ASSERT_STREQ(fake_plugin.config->name(), "fake");
  586. ASSERT_EQ(
  587. static_cast<RefCountedPtr<FakeCertificateProviderFactory::Config>>(
  588. fake_plugin.config)
  589. ->value(),
  590. 0);
  591. } else {
  592. EXPECT_TRUE(bootstrap.certificate_providers().empty());
  593. }
  594. }
  595. std::string TestTypeName(const ::testing::TestParamInfo<TestType>& info) {
  596. return info.param.AsString();
  597. }
  598. INSTANTIATE_TEST_SUITE_P(XdsBootstrap, XdsBootstrapTest,
  599. ::testing::Values(TestType(false), TestType(true)),
  600. &TestTypeName);
  601. } // namespace testing
  602. } // namespace grpc_core
  603. int main(int argc, char** argv) {
  604. ::testing::InitGoogleTest(&argc, argv);
  605. grpc::testing::TestEnvironment env(argc, argv);
  606. int ret = RUN_ALL_TESTS();
  607. return ret;
  608. }