xds_bootstrap_test.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  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 "src/core/ext/xds/xds_bootstrap.h"
  17. #include <regex>
  18. #include <gmock/gmock.h>
  19. #include <gtest/gtest.h>
  20. #include "absl/strings/numbers.h"
  21. #include "absl/strings/str_format.h"
  22. #include <grpc/grpc.h>
  23. #include <grpc/slice.h>
  24. #include "src/core/ext/xds/certificate_provider_registry.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. namespace {
  31. TEST(XdsBootstrapTest, Basic) {
  32. gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
  33. const char* json_str =
  34. "{"
  35. " \"xds_servers\": ["
  36. " {"
  37. " \"server_uri\": \"fake:///lb\","
  38. " \"channel_creds\": ["
  39. " {"
  40. " \"type\": \"fake\","
  41. " \"ignore\": 0"
  42. " }"
  43. " ],"
  44. " \"ignore\": 0"
  45. " },"
  46. " {"
  47. " \"server_uri\": \"ignored\","
  48. " \"channel_creds\": ["
  49. " {"
  50. " \"type\": \"ignored\","
  51. " \"ignore\": 0"
  52. " },"
  53. " {"
  54. " \"type\": \"fake\""
  55. " }"
  56. " ],"
  57. " \"ignore\": 0"
  58. " }"
  59. " ],"
  60. " \"authorities\": {"
  61. " \"xds.example.com\": {"
  62. " \"client_listener_resource_name_template\": "
  63. "\"xdstp://xds.example.com/envoy.config.listener.v3.Listener/grpc/server/"
  64. "%s\","
  65. " \"xds_servers\": ["
  66. " {"
  67. " \"server_uri\": \"fake:///xds_server\","
  68. " \"channel_creds\": ["
  69. " {"
  70. " \"type\": \"fake\""
  71. " }"
  72. " ],"
  73. " \"server_features\": [\"xds_v3\"]"
  74. " }"
  75. " ]"
  76. " },"
  77. " \"xds.example2.com\": {"
  78. " \"client_listener_resource_name_template\": "
  79. "\"xdstp://xds.example2.com/envoy.config.listener.v3.Listener/grpc/"
  80. "server/%s\","
  81. " \"xds_servers\": ["
  82. " {"
  83. " \"server_uri\": \"fake:///xds_server2\","
  84. " \"channel_creds\": ["
  85. " {"
  86. " \"type\": \"fake\""
  87. " }"
  88. " ],"
  89. " \"server_features\": [\"xds_v3\"]"
  90. " }"
  91. " ]"
  92. " }"
  93. " },"
  94. " \"node\": {"
  95. " \"id\": \"foo\","
  96. " \"cluster\": \"bar\","
  97. " \"locality\": {"
  98. " \"region\": \"milky_way\","
  99. " \"zone\": \"sol_system\","
  100. " \"sub_zone\": \"earth\","
  101. " \"ignore\": {}"
  102. " },"
  103. " \"metadata\": {"
  104. " \"foo\": 1,"
  105. " \"bar\": 2"
  106. " },"
  107. " \"ignore\": \"whee\""
  108. " },"
  109. " \"server_listener_resource_name_template\": \"example/resource\","
  110. " \"ignore\": {}"
  111. "}";
  112. grpc_error_handle error = GRPC_ERROR_NONE;
  113. Json json = Json::Parse(json_str, &error);
  114. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  115. XdsBootstrap bootstrap(std::move(json), &error);
  116. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  117. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  118. EXPECT_EQ(bootstrap.server().channel_creds_type, "fake");
  119. EXPECT_EQ(bootstrap.server().channel_creds_config.type(),
  120. Json::Type::JSON_NULL);
  121. EXPECT_EQ(bootstrap.authorities().size(), 2);
  122. const XdsBootstrap::Authority* authority1 =
  123. bootstrap.LookupAuthority("xds.example.com");
  124. ASSERT_NE(authority1, nullptr);
  125. EXPECT_EQ(authority1->client_listener_resource_name_template,
  126. "xdstp://xds.example.com/envoy.config.listener.v3.Listener/grpc/"
  127. "server/%s");
  128. EXPECT_EQ(authority1->xds_servers.size(), 1);
  129. EXPECT_EQ(authority1->xds_servers[0].server_uri, "fake:///xds_server");
  130. EXPECT_EQ(authority1->xds_servers[0].channel_creds_type, "fake");
  131. EXPECT_EQ(authority1->xds_servers[0].channel_creds_config.type(),
  132. Json::Type::JSON_NULL);
  133. const XdsBootstrap::Authority* authority2 =
  134. bootstrap.LookupAuthority("xds.example2.com");
  135. ASSERT_NE(authority2, nullptr);
  136. EXPECT_EQ(authority2->client_listener_resource_name_template,
  137. "xdstp://xds.example2.com/envoy.config.listener.v3.Listener/grpc/"
  138. "server/%s");
  139. EXPECT_EQ(authority2->xds_servers.size(), 1);
  140. EXPECT_EQ(authority2->xds_servers[0].server_uri, "fake:///xds_server2");
  141. EXPECT_EQ(authority2->xds_servers[0].channel_creds_type, "fake");
  142. EXPECT_EQ(authority2->xds_servers[0].channel_creds_config.type(),
  143. Json::Type::JSON_NULL);
  144. ASSERT_NE(bootstrap.node(), nullptr);
  145. EXPECT_EQ(bootstrap.node()->id, "foo");
  146. EXPECT_EQ(bootstrap.node()->cluster, "bar");
  147. EXPECT_EQ(bootstrap.node()->locality_region, "milky_way");
  148. EXPECT_EQ(bootstrap.node()->locality_zone, "sol_system");
  149. EXPECT_EQ(bootstrap.node()->locality_sub_zone, "earth");
  150. ASSERT_EQ(bootstrap.node()->metadata.type(), Json::Type::OBJECT);
  151. EXPECT_THAT(bootstrap.node()->metadata.object_value(),
  152. ::testing::ElementsAre(
  153. ::testing::Pair(
  154. ::testing::Eq("bar"),
  155. ::testing::AllOf(
  156. ::testing::Property(&Json::type, Json::Type::NUMBER),
  157. ::testing::Property(&Json::string_value, "2"))),
  158. ::testing::Pair(
  159. ::testing::Eq("foo"),
  160. ::testing::AllOf(
  161. ::testing::Property(&Json::type, Json::Type::NUMBER),
  162. ::testing::Property(&Json::string_value, "1")))));
  163. EXPECT_EQ(bootstrap.server_listener_resource_name_template(),
  164. "example/resource");
  165. gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
  166. }
  167. TEST(XdsBootstrapTest, ValidWithoutNode) {
  168. const char* json_str =
  169. "{"
  170. " \"xds_servers\": ["
  171. " {"
  172. " \"server_uri\": \"fake:///lb\","
  173. " \"channel_creds\": [{\"type\": \"fake\"}]"
  174. " }"
  175. " ]"
  176. "}";
  177. grpc_error_handle error = GRPC_ERROR_NONE;
  178. Json json = Json::Parse(json_str, &error);
  179. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  180. XdsBootstrap bootstrap(std::move(json), &error);
  181. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  182. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  183. EXPECT_EQ(bootstrap.server().channel_creds_type, "fake");
  184. EXPECT_EQ(bootstrap.node(), nullptr);
  185. }
  186. TEST(XdsBootstrapTest, InsecureCreds) {
  187. const char* json_str =
  188. "{"
  189. " \"xds_servers\": ["
  190. " {"
  191. " \"server_uri\": \"fake:///lb\","
  192. " \"channel_creds\": [{\"type\": \"insecure\"}]"
  193. " }"
  194. " ]"
  195. "}";
  196. grpc_error_handle error = GRPC_ERROR_NONE;
  197. Json json = Json::Parse(json_str, &error);
  198. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  199. XdsBootstrap bootstrap(std::move(json), &error);
  200. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  201. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  202. EXPECT_EQ(bootstrap.server().channel_creds_type, "insecure");
  203. EXPECT_EQ(bootstrap.node(), nullptr);
  204. }
  205. TEST(XdsBootstrapTest, GoogleDefaultCreds) {
  206. // Generate call creds file needed by GoogleDefaultCreds.
  207. const char token_str[] =
  208. "{ \"client_id\": \"32555999999.apps.googleusercontent.com\","
  209. " \"client_secret\": \"EmssLNjJy1332hD4KFsecret\","
  210. " \"refresh_token\": \"1/Blahblasj424jladJDSGNf-u4Sua3HDA2ngjd42\","
  211. " \"type\": \"authorized_user\"}";
  212. char* creds_file_name;
  213. FILE* creds_file = gpr_tmpfile("xds_bootstrap_test", &creds_file_name);
  214. ASSERT_NE(creds_file_name, nullptr);
  215. ASSERT_NE(creds_file, nullptr);
  216. ASSERT_EQ(fwrite(token_str, 1, sizeof(token_str), creds_file),
  217. sizeof(token_str));
  218. fclose(creds_file);
  219. gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, creds_file_name);
  220. gpr_free(creds_file_name);
  221. // Now run test.
  222. const char* json_str =
  223. "{"
  224. " \"xds_servers\": ["
  225. " {"
  226. " \"server_uri\": \"fake:///lb\","
  227. " \"channel_creds\": [{\"type\": \"google_default\"}]"
  228. " }"
  229. " ]"
  230. "}";
  231. grpc_error_handle error = GRPC_ERROR_NONE;
  232. Json json = Json::Parse(json_str, &error);
  233. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  234. XdsBootstrap bootstrap(std::move(json), &error);
  235. EXPECT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  236. EXPECT_EQ(bootstrap.server().server_uri, "fake:///lb");
  237. EXPECT_EQ(bootstrap.server().channel_creds_type, "google_default");
  238. EXPECT_EQ(bootstrap.node(), nullptr);
  239. }
  240. TEST(XdsBootstrapTest, MissingChannelCreds) {
  241. const char* json_str =
  242. "{"
  243. " \"xds_servers\": ["
  244. " {"
  245. " \"server_uri\": \"fake:///lb\""
  246. " }"
  247. " ]"
  248. "}";
  249. grpc_error_handle error = GRPC_ERROR_NONE;
  250. Json json = Json::Parse(json_str, &error);
  251. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  252. XdsBootstrap bootstrap(std::move(json), &error);
  253. EXPECT_THAT(
  254. grpc_error_std_string(error),
  255. ::testing::ContainsRegex("field:channel_creds error:does not exist."));
  256. GRPC_ERROR_UNREF(error);
  257. }
  258. TEST(XdsBootstrapTest, NoKnownChannelCreds) {
  259. const char* json_str =
  260. "{"
  261. " \"xds_servers\": ["
  262. " {"
  263. " \"server_uri\": \"fake:///lb\","
  264. " \"channel_creds\": [{\"type\": \"unknown\"}]"
  265. " }"
  266. " ]"
  267. "}";
  268. grpc_error_handle error = GRPC_ERROR_NONE;
  269. Json json = Json::Parse(json_str, &error);
  270. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  271. XdsBootstrap bootstrap(std::move(json), &error);
  272. EXPECT_THAT(grpc_error_std_string(error),
  273. ::testing::ContainsRegex(
  274. "no known creds type found in \"channel_creds\""));
  275. GRPC_ERROR_UNREF(error);
  276. }
  277. TEST(XdsBootstrapTest, MissingXdsServers) {
  278. grpc_error_handle error = GRPC_ERROR_NONE;
  279. Json json = Json::Parse("{}", &error);
  280. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  281. XdsBootstrap bootstrap(std::move(json), &error);
  282. EXPECT_THAT(grpc_error_std_string(error),
  283. ::testing::ContainsRegex("\"xds_servers\" field not present"));
  284. GRPC_ERROR_UNREF(error);
  285. }
  286. TEST(XdsBootstrapTest, TopFieldsWrongTypes) {
  287. const char* json_str =
  288. "{"
  289. " \"xds_servers\":1,"
  290. " \"node\":1,"
  291. " \"server_listener_resource_name_template\":1,"
  292. " \"certificate_providers\":1"
  293. "}";
  294. grpc_error_handle error = GRPC_ERROR_NONE;
  295. Json json = Json::Parse(json_str, &error);
  296. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  297. XdsBootstrap bootstrap(std::move(json), &error);
  298. EXPECT_THAT(grpc_error_std_string(error),
  299. ::testing::ContainsRegex("\"xds_servers\" field is not an array.*"
  300. "\"node\" field is not an object.*"
  301. "\"server_listener_resource_name_"
  302. "template\" field is not a string.*"));
  303. EXPECT_THAT(grpc_error_std_string(error),
  304. ::testing::ContainsRegex(
  305. "\"certificate_providers\" field is not an object"));
  306. GRPC_ERROR_UNREF(error);
  307. }
  308. TEST(XdsBootstrapTest, XdsServerMissingServerUri) {
  309. const char* json_str =
  310. "{"
  311. " \"xds_servers\":[{}]"
  312. "}";
  313. grpc_error_handle error = GRPC_ERROR_NONE;
  314. Json json = Json::Parse(json_str, &error);
  315. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  316. XdsBootstrap bootstrap(std::move(json), &error);
  317. EXPECT_THAT(
  318. grpc_error_std_string(error),
  319. ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
  320. "errors parsing index 0.*"
  321. "errors parsing xds server.*"
  322. "field:server_uri error:does not exist."));
  323. GRPC_ERROR_UNREF(error);
  324. }
  325. TEST(XdsBootstrapTest, XdsServerUriAndCredsWrongTypes) {
  326. const char* json_str =
  327. "{"
  328. " \"xds_servers\":["
  329. " {"
  330. " \"server_uri\":1,"
  331. " \"channel_creds\":1"
  332. " }"
  333. " ]"
  334. "}";
  335. grpc_error_handle error = GRPC_ERROR_NONE;
  336. Json json = Json::Parse(json_str, &error);
  337. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  338. XdsBootstrap bootstrap(std::move(json), &error);
  339. EXPECT_THAT(grpc_error_std_string(error),
  340. ::testing::ContainsRegex(
  341. "errors parsing \"xds_servers\" array.*"
  342. "errors parsing index 0.*"
  343. "errors parsing xds server.*"
  344. "field:server_uri error:type should be STRING.*"
  345. "field:channel_creds error:type should be ARRAY"));
  346. GRPC_ERROR_UNREF(error);
  347. }
  348. TEST(XdsBootstrapTest, ChannelCredsFieldsWrongTypes) {
  349. const char* json_str =
  350. "{"
  351. " \"xds_servers\":["
  352. " {"
  353. " \"server_uri\":\"foo\","
  354. " \"channel_creds\":["
  355. " {"
  356. " \"type\":0,"
  357. " \"config\":1"
  358. " }"
  359. " ]"
  360. " }"
  361. " ]"
  362. "}";
  363. grpc_error_handle error = GRPC_ERROR_NONE;
  364. Json json = Json::Parse(json_str, &error);
  365. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  366. XdsBootstrap bootstrap(std::move(json), &error);
  367. EXPECT_THAT(
  368. grpc_error_std_string(error),
  369. ::testing::ContainsRegex("errors parsing \"xds_servers\" array.*"
  370. "errors parsing index 0.*"
  371. "errors parsing xds server.*"
  372. "errors parsing \"channel_creds\" array.*"
  373. "errors parsing index 0.*"
  374. "field:type error:type should be STRING.*"
  375. "field:config error:type should be OBJECT"));
  376. GRPC_ERROR_UNREF(error);
  377. }
  378. TEST(XdsBootstrapTest, NodeFieldsWrongTypes) {
  379. const char* json_str =
  380. "{"
  381. " \"node\":{"
  382. " \"id\":0,"
  383. " \"cluster\":0,"
  384. " \"locality\":0,"
  385. " \"metadata\":0"
  386. " }"
  387. "}";
  388. grpc_error_handle error = GRPC_ERROR_NONE;
  389. Json json = Json::Parse(json_str, &error);
  390. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  391. XdsBootstrap bootstrap(std::move(json), &error);
  392. EXPECT_THAT(grpc_error_std_string(error),
  393. ::testing::ContainsRegex("errors parsing \"node\" object.*"
  394. "\"id\" field is not a string.*"
  395. "\"cluster\" field is not a string.*"
  396. "\"locality\" field is not an object.*"
  397. "\"metadata\" field is not an object"));
  398. GRPC_ERROR_UNREF(error);
  399. }
  400. TEST(XdsBootstrapTest, LocalityFieldsWrongType) {
  401. const char* json_str =
  402. "{"
  403. " \"node\":{"
  404. " \"locality\":{"
  405. " \"region\":0,"
  406. " \"zone\":0,"
  407. " \"sub_zone\":0"
  408. " }"
  409. " }"
  410. "}";
  411. grpc_error_handle error = GRPC_ERROR_NONE;
  412. Json json = Json::Parse(json_str, &error);
  413. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  414. XdsBootstrap bootstrap(std::move(json), &error);
  415. EXPECT_THAT(grpc_error_std_string(error),
  416. ::testing::ContainsRegex("errors parsing \"node\" object.*"
  417. "errors parsing \"locality\" object.*"
  418. "\"region\" field is not a string.*"
  419. "\"zone\" field is not a string.*"
  420. "\"sub_zone\" field is not a string"));
  421. GRPC_ERROR_UNREF(error);
  422. }
  423. TEST(XdsBootstrapTest, CertificateProvidersElementWrongType) {
  424. const char* json_str =
  425. "{"
  426. " \"xds_servers\": ["
  427. " {"
  428. " \"server_uri\": \"fake:///lb\","
  429. " \"channel_creds\": [{\"type\": \"fake\"}]"
  430. " }"
  431. " ],"
  432. " \"certificate_providers\": {"
  433. " \"plugin\":1"
  434. " }"
  435. "}";
  436. grpc_error_handle error = GRPC_ERROR_NONE;
  437. Json json = Json::Parse(json_str, &error);
  438. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  439. XdsBootstrap bootstrap(std::move(json), &error);
  440. EXPECT_THAT(grpc_error_std_string(error),
  441. ::testing::ContainsRegex(
  442. "errors parsing \"certificate_providers\" object.*"
  443. "element \"plugin\" is not an object"));
  444. GRPC_ERROR_UNREF(error);
  445. }
  446. TEST(XdsBootstrapTest, CertificateProvidersPluginNameWrongType) {
  447. const char* json_str =
  448. "{"
  449. " \"xds_servers\": ["
  450. " {"
  451. " \"server_uri\": \"fake:///lb\","
  452. " \"channel_creds\": [{\"type\": \"fake\"}]"
  453. " }"
  454. " ],"
  455. " \"certificate_providers\": {"
  456. " \"plugin\": {"
  457. " \"plugin_name\":1"
  458. " }"
  459. " }"
  460. "}";
  461. grpc_error_handle error = GRPC_ERROR_NONE;
  462. Json json = Json::Parse(json_str, &error);
  463. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  464. XdsBootstrap bootstrap(std::move(json), &error);
  465. EXPECT_THAT(grpc_error_std_string(error),
  466. ::testing::ContainsRegex(
  467. "errors parsing \"certificate_providers\" object.*"
  468. "errors parsing element \"plugin\".*"
  469. "\"plugin_name\" field is not a string"));
  470. GRPC_ERROR_UNREF(error);
  471. }
  472. TEST(XdsBootstrapTest, CertificateProvidersUnrecognizedPluginName) {
  473. const char* json_str =
  474. "{"
  475. " \"xds_servers\": ["
  476. " {"
  477. " \"server_uri\": \"fake:///lb\","
  478. " \"channel_creds\": [{\"type\": \"fake\"}]"
  479. " }"
  480. " ],"
  481. " \"certificate_providers\": {"
  482. " \"plugin\": {"
  483. " \"plugin_name\":\"unknown\""
  484. " }"
  485. " }"
  486. "}";
  487. grpc_error_handle error = GRPC_ERROR_NONE;
  488. Json json = Json::Parse(json_str, &error);
  489. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  490. XdsBootstrap bootstrap(std::move(json), &error);
  491. EXPECT_THAT(grpc_error_std_string(error),
  492. ::testing::ContainsRegex(
  493. "errors parsing \"certificate_providers\" object.*"
  494. "errors parsing element \"plugin\".*"
  495. "Unrecognized plugin name: unknown"));
  496. GRPC_ERROR_UNREF(error);
  497. }
  498. TEST(XdsBootstrapTest, AuthorityXdsServerInvalidResourceTemplate) {
  499. gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
  500. const char* json_str =
  501. "{"
  502. " \"xds_servers\": ["
  503. " {"
  504. " \"server_uri\": \"fake:///lb\","
  505. " \"channel_creds\": [{\"type\": \"fake\"}]"
  506. " }"
  507. " ],"
  508. " \"authorities\": {"
  509. " \"xds.example.com\": {"
  510. " \"client_listener_resource_name_template\": "
  511. "\"xds://xds.example.com/envoy.config.listener.v3.Listener/grpc/server/"
  512. "%s\","
  513. " \"xds_servers\": ["
  514. " {"
  515. " \"server_uri\": \"fake:///xds_server\","
  516. " \"channel_creds\": ["
  517. " {"
  518. " \"type\": \"fake\""
  519. " }"
  520. " ],"
  521. " \"server_features\": [\"xds_v3\"]"
  522. " }"
  523. " ]"
  524. " }"
  525. " }"
  526. "}";
  527. grpc_error_handle error = GRPC_ERROR_NONE;
  528. Json json = Json::Parse(json_str, &error);
  529. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  530. XdsBootstrap bootstrap(std::move(json), &error);
  531. EXPECT_THAT(grpc_error_std_string(error),
  532. ::testing::ContainsRegex(
  533. "errors parsing \"authorities\".*"
  534. "errors parsing authority xds.example.com.*"
  535. "field must begin with \"xdstp://xds.example.com/\""));
  536. GRPC_ERROR_UNREF(error);
  537. gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
  538. }
  539. TEST(XdsBootstrapTest, AuthorityXdsServerMissingServerUri) {
  540. gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
  541. const char* json_str =
  542. "{"
  543. " \"xds_servers\": ["
  544. " {"
  545. " \"server_uri\": \"fake:///lb\","
  546. " \"channel_creds\": [{\"type\": \"fake\"}]"
  547. " }"
  548. " ],"
  549. " \"authorities\": {"
  550. " \"xds.example.com\": {"
  551. " \"client_listener_resource_name_template\": "
  552. "\"xdstp://xds.example.com/envoy.config.listener.v3.Listener/grpc/server/"
  553. "%s\","
  554. " \"xds_servers\":[{}]"
  555. " }"
  556. " }"
  557. "}";
  558. grpc_error_handle error = GRPC_ERROR_NONE;
  559. Json json = Json::Parse(json_str, &error);
  560. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  561. XdsBootstrap bootstrap(std::move(json), &error);
  562. EXPECT_THAT(
  563. grpc_error_std_string(error),
  564. ::testing::ContainsRegex("errors parsing \"authorities\".*"
  565. "errors parsing authority xds.example.com.*"
  566. "errors parsing \"xds_servers\" array.*"
  567. "errors parsing index 0.*"
  568. "errors parsing xds server.*"
  569. "field:server_uri error:does not exist."));
  570. GRPC_ERROR_UNREF(error);
  571. gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
  572. }
  573. class FakeCertificateProviderFactory : public CertificateProviderFactory {
  574. public:
  575. class Config : public CertificateProviderFactory::Config {
  576. public:
  577. explicit Config(int value) : value_(value) {}
  578. int value() const { return value_; }
  579. const char* name() const override { return "fake"; }
  580. std::string ToString() const override {
  581. return absl::StrFormat(
  582. "{\n"
  583. " value=%d"
  584. "}",
  585. value_);
  586. }
  587. private:
  588. int value_;
  589. };
  590. const char* name() const override { return "fake"; }
  591. RefCountedPtr<CertificateProviderFactory::Config>
  592. CreateCertificateProviderConfig(const Json& config_json,
  593. grpc_error_handle* error) override {
  594. std::vector<grpc_error_handle> error_list;
  595. EXPECT_EQ(config_json.type(), Json::Type::OBJECT);
  596. auto it = config_json.object_value().find("value");
  597. if (it == config_json.object_value().end()) {
  598. return MakeRefCounted<FakeCertificateProviderFactory::Config>(0);
  599. } else if (it->second.type() != Json::Type::NUMBER) {
  600. *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
  601. "field:config field:value not of type number");
  602. } else {
  603. int value = 0;
  604. EXPECT_TRUE(absl::SimpleAtoi(it->second.string_value(), &value));
  605. return MakeRefCounted<FakeCertificateProviderFactory::Config>(value);
  606. }
  607. return nullptr;
  608. }
  609. RefCountedPtr<grpc_tls_certificate_provider> CreateCertificateProvider(
  610. RefCountedPtr<CertificateProviderFactory::Config> /*config*/) override {
  611. return nullptr;
  612. }
  613. };
  614. TEST(XdsBootstrapTest, CertificateProvidersFakePluginParsingError) {
  615. const char* json_str =
  616. "{"
  617. " \"xds_servers\": ["
  618. " {"
  619. " \"server_uri\": \"fake:///lb\","
  620. " \"channel_creds\": [{\"type\": \"fake\"}]"
  621. " }"
  622. " ],"
  623. " \"certificate_providers\": {"
  624. " \"fake_plugin\": {"
  625. " \"plugin_name\": \"fake\","
  626. " \"config\": {"
  627. " \"value\": \"10\""
  628. " }"
  629. " }"
  630. " }"
  631. "}";
  632. grpc_error_handle error = GRPC_ERROR_NONE;
  633. Json json = Json::Parse(json_str, &error);
  634. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  635. XdsBootstrap bootstrap(std::move(json), &error);
  636. EXPECT_THAT(grpc_error_std_string(error),
  637. ::testing::ContainsRegex(
  638. "errors parsing \"certificate_providers\" object.*"
  639. "errors parsing element \"fake_plugin\".*"
  640. "field:config field:value not of type number"));
  641. GRPC_ERROR_UNREF(error);
  642. }
  643. TEST(XdsBootstrapTest, CertificateProvidersFakePluginParsingSuccess) {
  644. const char* json_str =
  645. "{"
  646. " \"xds_servers\": ["
  647. " {"
  648. " \"server_uri\": \"fake:///lb\","
  649. " \"channel_creds\": [{\"type\": \"fake\"}]"
  650. " }"
  651. " ],"
  652. " \"certificate_providers\": {"
  653. " \"fake_plugin\": {"
  654. " \"plugin_name\": \"fake\","
  655. " \"config\": {"
  656. " \"value\": 10"
  657. " }"
  658. " }"
  659. " }"
  660. "}";
  661. grpc_error_handle error = GRPC_ERROR_NONE;
  662. Json json = Json::Parse(json_str, &error);
  663. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  664. XdsBootstrap bootstrap(std::move(json), &error);
  665. ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_std_string(error);
  666. const CertificateProviderStore::PluginDefinition& fake_plugin =
  667. bootstrap.certificate_providers().at("fake_plugin");
  668. ASSERT_EQ(fake_plugin.plugin_name, "fake");
  669. ASSERT_STREQ(fake_plugin.config->name(), "fake");
  670. ASSERT_EQ(static_cast<RefCountedPtr<FakeCertificateProviderFactory::Config>>(
  671. fake_plugin.config)
  672. ->value(),
  673. 10);
  674. }
  675. TEST(XdsBootstrapTest, CertificateProvidersFakePluginEmptyConfig) {
  676. const char* json_str =
  677. "{"
  678. " \"xds_servers\": ["
  679. " {"
  680. " \"server_uri\": \"fake:///lb\","
  681. " \"channel_creds\": [{\"type\": \"fake\"}]"
  682. " }"
  683. " ],"
  684. " \"certificate_providers\": {"
  685. " \"fake_plugin\": {"
  686. " \"plugin_name\": \"fake\""
  687. " }"
  688. " }"
  689. "}";
  690. grpc_error_handle error = GRPC_ERROR_NONE;
  691. Json json = Json::Parse(json_str, &error);
  692. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  693. XdsBootstrap bootstrap(std::move(json), &error);
  694. ASSERT_TRUE(error == GRPC_ERROR_NONE) << grpc_error_std_string(error);
  695. const CertificateProviderStore::PluginDefinition& fake_plugin =
  696. bootstrap.certificate_providers().at("fake_plugin");
  697. ASSERT_EQ(fake_plugin.plugin_name, "fake");
  698. ASSERT_STREQ(fake_plugin.config->name(), "fake");
  699. ASSERT_EQ(static_cast<RefCountedPtr<FakeCertificateProviderFactory::Config>>(
  700. fake_plugin.config)
  701. ->value(),
  702. 0);
  703. }
  704. TEST(XdsBootstrapTest, XdsServerToJsonAndParse) {
  705. gpr_setenv("GRPC_EXPERIMENTAL_XDS_FEDERATION", "true");
  706. const char* json_str =
  707. " {"
  708. " \"server_uri\": \"fake:///lb\","
  709. " \"channel_creds\": ["
  710. " {"
  711. " \"type\": \"fake\","
  712. " \"ignore\": 0"
  713. " }"
  714. " ],"
  715. " \"ignore\": 0"
  716. " }";
  717. grpc_error_handle error = GRPC_ERROR_NONE;
  718. Json json = Json::Parse(json_str, &error);
  719. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  720. XdsBootstrap::XdsServer xds_server =
  721. XdsBootstrap::XdsServer::Parse(json, &error);
  722. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  723. Json::Object output = xds_server.ToJson();
  724. XdsBootstrap::XdsServer output_xds_server =
  725. XdsBootstrap::XdsServer::Parse(output, &error);
  726. ASSERT_EQ(error, GRPC_ERROR_NONE) << grpc_error_std_string(error);
  727. gpr_unsetenv("GRPC_EXPERIMENTAL_XDS_FEDERATION");
  728. }
  729. } // namespace
  730. } // namespace testing
  731. } // namespace grpc_core
  732. int main(int argc, char** argv) {
  733. ::testing::InitGoogleTest(&argc, argv);
  734. grpc::testing::TestEnvironment env(argc, argv);
  735. grpc_init();
  736. grpc_core::CertificateProviderRegistry::RegisterCertificateProviderFactory(
  737. absl::make_unique<grpc_core::testing::FakeCertificateProviderFactory>());
  738. int ret = RUN_ALL_TESTS();
  739. grpc_shutdown();
  740. return ret;
  741. }