protocol_parser_json_unittest.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/update_client/protocol_parser_json.h"
  5. #include <memory>
  6. #include "testing/gtest/include/gtest/gtest.h"
  7. namespace update_client {
  8. const char* kJSONValid = R"()]}'
  9. {"response":{
  10. "protocol":"3.1",
  11. "app":[
  12. {"appid":"12345",
  13. "status":"ok",
  14. "updatecheck":{
  15. "status":"ok",
  16. "urls":{"url":[{"codebase":"http://example.com/"},
  17. {"codebasediff":"http://diff.example.com/"}]},
  18. "manifest":{
  19. "version":"1.2.3.4",
  20. "prodversionmin":"2.0.143.0",
  21. "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}}
  22. }
  23. }
  24. ]
  25. }})";
  26. const char* kJSONHash = R"()]}'
  27. {"response":{
  28. "protocol":"3.1",
  29. "app":[
  30. {"appid":"12345",
  31. "status":"ok",
  32. "updatecheck":{
  33. "status":"ok",
  34. "urls":{"url":[{"codebase":"http://example.com/"}]},
  35. "manifest":{
  36. "version":"1.2.3.4",
  37. "prodversionmin":"2.0.143.0",
  38. "packages":{"package":[{"name":"extension_1_2_3_4.crx",
  39. "hash_sha256":"1234",
  40. "hashdiff_sha256":"5678"}]}}
  41. }
  42. }
  43. ]
  44. }})";
  45. const char* kJSONInvalidSizes = R"()]}'
  46. {"response":{
  47. "protocol":"3.1",
  48. "app":[
  49. {"appid":"12345",
  50. "status":"ok",
  51. "updatecheck":{
  52. "status":"ok",
  53. "urls":{"url":[{"codebase":"http://example.com/"}]},
  54. "manifest":{
  55. "version":"1.2.3.4",
  56. "prodversionmin":"2.0.143.0",
  57. "packages":{"package":[{"name":"1","size":1234},
  58. {"name":"2","size":9007199254740991},
  59. {"name":"3","size":-1234},
  60. {"name":"4"},
  61. {"name":"5","size":"-a"},
  62. {"name":"6","size":-123467890123456789},
  63. {"name":"7","size":123467890123456789},
  64. {"name":"8","sizediff":1234},
  65. {"name":"9","sizediff":9007199254740991},
  66. {"name":"10","sizediff":-1234},
  67. {"name":"11","sizediff":"-a"},
  68. {"name":"12","sizediff":-123467890123456789},
  69. {"name":"13","sizediff":123467890123456789}]}}
  70. }
  71. }
  72. ]
  73. }})";
  74. const char* kJSONInvalidMissingCodebase = R"()]}'
  75. {"response":{
  76. "protocol":"3.1",
  77. "app":[
  78. {"appid":"12345",
  79. "status":"ok",
  80. "updatecheck":{
  81. "status":"ok",
  82. "urls":{"url":[{"codebasediff":"http://diff.example.com"}]},
  83. "manifest":{
  84. "version":"1.2.3.4",
  85. "prodversionmin":"2.0.143.0",
  86. "packages":{"package":[{"namediff":"extension_1_2_3_4.crx"}]}}
  87. }
  88. }
  89. ]
  90. }})";
  91. const char* kJSONInvalidMissingManifest = R"()]}'
  92. {"response":{
  93. "protocol":"3.1",
  94. "app":[
  95. {"appid":"12345",
  96. "status":"ok",
  97. "updatecheck":{
  98. "status":"ok",
  99. "urls":{"url":[{"codebase":"http://localhost/download/"}]}
  100. }
  101. }
  102. ]
  103. }})";
  104. const char* kJSONMissingAppId = R"()]}'
  105. {"response":{
  106. "protocol":"3.1",
  107. "app":[
  108. {"status":"ok",
  109. "updatecheck":{
  110. "status":"ok",
  111. "urls":{"url":[{"codebase":"http://localhost/download/"}]}
  112. }
  113. }
  114. ]
  115. }})";
  116. const char* kJSONInvalidCodebase = R"()]}'
  117. {"response":{
  118. "protocol":"3.1",
  119. "app":[
  120. {"appid":"12345",
  121. "status":"ok",
  122. "updatecheck":{
  123. "status":"ok",
  124. "urls":{"url":[{"codebase":"example.com/extension_1.2.3.4.crx",
  125. "version":"1.2.3.4"}]}
  126. }
  127. }
  128. ]
  129. }})";
  130. const char* kJSONMissingVersion = R"()]}'
  131. {"response":{
  132. "protocol":"3.1",
  133. "app":[
  134. {"appid":"12345",
  135. "status":"ok",
  136. "updatecheck":{
  137. "status":"ok",
  138. "urls":{"url":[{"codebase":"http://localhost/download/"}]},
  139. "manifest":{
  140. "packages":{"package":[{"name":"jebgalgnebhfojomionfpkfelancnnkf.crx"}]}}
  141. }
  142. }
  143. ]
  144. }})";
  145. const char* kJSONInvalidVersion = R"()]}'
  146. {"response":{
  147. "protocol":"3.1",
  148. "app":[
  149. {"appid":"12345",
  150. "status":"ok",
  151. "updatecheck":{
  152. "status":"ok",
  153. "urls":{"url":[{"codebase":"http://localhost/download/"}]},
  154. "manifest":{
  155. "version":"1.2.3.a",
  156. "packages":{"package":[{"name":"jebgalgnebhfojomionfpkfelancnnkf.crx"}]}}
  157. }
  158. }
  159. ]
  160. }})";
  161. // Includes a <daystart> tag.
  162. const char* kJSONWithDaystart = R"()]}'
  163. {"response":{
  164. "protocol":"3.1",
  165. "daystart":{"elapsed_seconds":456},
  166. "app":[
  167. {"appid":"12345",
  168. "status":"ok",
  169. "updatecheck":{
  170. "status":"ok",
  171. "urls":{"url":[{"codebase":"http://example.com/"},
  172. {"codebasediff":"http://diff.example.com/"}]},
  173. "manifest":{
  174. "version":"1.2.3.4",
  175. "prodversionmin":"2.0.143.0",
  176. "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}}
  177. }
  178. }
  179. ]
  180. }})";
  181. // Indicates no updates available.
  182. const char* kJSONNoUpdate = R"()]}'
  183. {"response":{
  184. "protocol":"3.1",
  185. "app":[
  186. {"appid":"12345",
  187. "status":"ok",
  188. "updatecheck":{
  189. "status":"noupdate"
  190. }
  191. }
  192. ]
  193. }})";
  194. // Includes two app objects, one app with an error.
  195. const char* kJSONTwoAppsOneError = R"()]}'
  196. {"response":{
  197. "protocol":"3.1",
  198. "daystart":{"elapsed_seconds":456},
  199. "app":[
  200. {"appid":"aaaaaaaa",
  201. "status":"error-unknownApplication",
  202. "updatecheck":{"status":"error-internal"}
  203. },
  204. {"appid":"bbbbbbbb",
  205. "status":"ok",
  206. "updatecheck":{
  207. "status":"ok",
  208. "urls":{"url":[{"codebase":"http://example.com/"}]},
  209. "manifest":{
  210. "version":"1.2.3.4",
  211. "prodversionmin":"2.0.143.0",
  212. "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}}
  213. }
  214. }
  215. ]
  216. }})";
  217. // Includes two <app> tags, both of which set the cohort.
  218. const char* kJSONTwoAppsSetCohort = R"()]}'
  219. {"response":{
  220. "protocol":"3.1",
  221. "daystart":{"elapsed_seconds":456},
  222. "app":[
  223. {"appid":"aaaaaaaa",
  224. "cohort":"1:2q3/",
  225. "updatecheck":{"status":"noupdate"}
  226. },
  227. {"appid":"bbbbbbbb",
  228. "cohort":"1:33z@0.33",
  229. "cohortname":"cname",
  230. "updatecheck":{
  231. "status":"ok",
  232. "urls":{"url":[{"codebase":"http://example.com/"}]},
  233. "manifest":{
  234. "version":"1.2.3.4",
  235. "prodversionmin":"2.0.143.0",
  236. "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}}
  237. }
  238. }
  239. ]
  240. }})";
  241. // Includes a run action for an update check with status='ok'.
  242. const char* kJSONUpdateCheckStatusOkWithRunAction = R"()]}'
  243. {"response":{
  244. "protocol":"3.1",
  245. "app":[
  246. {"appid":"12345",
  247. "updatecheck":{
  248. "status":"ok",
  249. "actions":{"action":[{"run":"this"}]},
  250. "urls":{"url":[{"codebase":"http://example.com/"},
  251. {"codebasediff":"http://diff.example.com/"}]},
  252. "manifest":{
  253. "version":"1.2.3.4",
  254. "prodversionmin":"2.0.143.0",
  255. "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}}
  256. }
  257. }
  258. ]
  259. }})";
  260. // Includes a run action for an update check with status='noupdate'.
  261. const char* kJSONUpdateCheckStatusNoUpdateWithRunAction = R"()]}'
  262. {"response":{
  263. "protocol":"3.1",
  264. "app":[
  265. {"appid":"12345",
  266. "updatecheck":{
  267. "status":"noupdate",
  268. "actions":{"action":[{"run":"this"}]}
  269. }
  270. }
  271. ]
  272. }})";
  273. // Includes a run action for an update check with status='error'.
  274. const char* kJSONUpdateCheckStatusErrorWithRunAction = R"()]}'
  275. {"response":{
  276. "protocol":"3.1",
  277. "app":[
  278. {"appid":"12345",
  279. "updatecheck":{
  280. "status":"error-osnotsupported",
  281. "actions":{"action":[{"run":"this"}]}
  282. }
  283. }
  284. ]
  285. }})";
  286. // Includes four app objects with status different than 'ok'.
  287. const char* kJSONAppsStatusError = R"()]}'
  288. {"response":{
  289. "protocol":"3.1",
  290. "app":[
  291. {"appid":"aaaaaaaa",
  292. "status":"error-unknownApplication",
  293. "updatecheck":{"status":"error-internal"}
  294. },
  295. {"appid":"bbbbbbbb",
  296. "status":"restricted",
  297. "updatecheck":{"status":"error-internal"}
  298. },
  299. {"appid":"cccccccc",
  300. "status":"error-invalidAppId",
  301. "updatecheck":{"status":"error-internal"}
  302. },
  303. {"appid":"dddddddd",
  304. "status":"foobar",
  305. "updatecheck":{"status":"error-internal"}
  306. }
  307. ]
  308. }})";
  309. // Includes a manifest |run| value for an update check with status='ok'. Also
  310. // includes install data in the `data` element.
  311. const char* kJSONManifestRun = R"()]}'
  312. {"response":{
  313. "protocol":"3.1",
  314. "app":[
  315. {"appid":"12345",
  316. "data":[{
  317. "status":"ok",
  318. "name":"install",
  319. "index":"foobar_install_data_index",
  320. "#text":"sampledata"
  321. }],
  322. "updatecheck":{
  323. "status":"ok",
  324. "urls":{"url":[{"codebase":"http://example.com/"},
  325. {"codebasediff":"http://diff.example.com/"}]},
  326. "manifest":{
  327. "version":"1.2.3.4",
  328. "prodversionmin":"2.0.143.0",
  329. "run":"UpdaterSetup.exe",
  330. "arguments":"--arg1 --arg2",
  331. "packages":{"package":[{"name":"extension_1_2_3_4.crx"}]}}
  332. }
  333. }
  334. ]
  335. }})";
  336. // Includes two custom response attributes in the update_check.
  337. const char* kJSONCustomAttributes = R"()]}'
  338. {"response":{
  339. "protocol":"3.1",
  340. "app":[
  341. {"appid":"12345",
  342. "updatecheck":{
  343. "_example1":"example_value1",
  344. "_example2":"example_value2",
  345. "_example_bad": {"value": "bad-non-string-value"},
  346. "_example_bad2": 15,
  347. "status":"noupdate"
  348. }
  349. }
  350. ]
  351. }})";
  352. TEST(UpdateClientProtocolParserJSONTest, Parse) {
  353. const auto parser = std::make_unique<ProtocolParserJSON>();
  354. // Test parsing of a number of invalid JSON cases
  355. EXPECT_FALSE(parser->Parse(std::string()));
  356. EXPECT_FALSE(parser->errors().empty());
  357. EXPECT_TRUE(parser->Parse(kJSONMissingAppId));
  358. EXPECT_TRUE(parser->results().list.empty());
  359. EXPECT_FALSE(parser->errors().empty());
  360. EXPECT_TRUE(parser->Parse(kJSONInvalidCodebase));
  361. EXPECT_TRUE(parser->results().list.empty());
  362. EXPECT_FALSE(parser->errors().empty());
  363. EXPECT_TRUE(parser->Parse(kJSONMissingVersion));
  364. EXPECT_TRUE(parser->results().list.empty());
  365. EXPECT_FALSE(parser->errors().empty());
  366. EXPECT_TRUE(parser->Parse(kJSONInvalidVersion));
  367. EXPECT_TRUE(parser->results().list.empty());
  368. EXPECT_FALSE(parser->errors().empty());
  369. EXPECT_TRUE(parser->Parse(kJSONInvalidMissingCodebase));
  370. EXPECT_TRUE(parser->results().list.empty());
  371. EXPECT_FALSE(parser->errors().empty());
  372. EXPECT_TRUE(parser->Parse(kJSONInvalidMissingManifest));
  373. EXPECT_TRUE(parser->results().list.empty());
  374. EXPECT_FALSE(parser->errors().empty());
  375. {
  376. // Parse some valid XML, and check that all params came out as expected.
  377. EXPECT_TRUE(parser->Parse(kJSONValid));
  378. EXPECT_TRUE(parser->errors().empty());
  379. EXPECT_EQ(1u, parser->results().list.size());
  380. const auto* first_result = &parser->results().list[0];
  381. EXPECT_STREQ("ok", first_result->status.c_str());
  382. EXPECT_EQ(1u, first_result->crx_urls.size());
  383. EXPECT_EQ(GURL("http://example.com/"), first_result->crx_urls[0]);
  384. EXPECT_EQ(GURL("http://diff.example.com/"), first_result->crx_diffurls[0]);
  385. EXPECT_EQ("1.2.3.4", first_result->manifest.version);
  386. EXPECT_EQ("2.0.143.0", first_result->manifest.browser_min_version);
  387. EXPECT_EQ(1u, first_result->manifest.packages.size());
  388. EXPECT_EQ("extension_1_2_3_4.crx", first_result->manifest.packages[0].name);
  389. }
  390. {
  391. // Parse xml with hash value.
  392. EXPECT_TRUE(parser->Parse(kJSONHash));
  393. EXPECT_TRUE(parser->errors().empty());
  394. EXPECT_FALSE(parser->results().list.empty());
  395. const auto* first_result = &parser->results().list[0];
  396. EXPECT_FALSE(first_result->manifest.packages.empty());
  397. EXPECT_EQ("1234", first_result->manifest.packages[0].hash_sha256);
  398. EXPECT_EQ("5678", first_result->manifest.packages[0].hashdiff_sha256);
  399. }
  400. {
  401. // Parse xml with package size value.
  402. EXPECT_TRUE(parser->Parse(kJSONInvalidSizes));
  403. EXPECT_TRUE(parser->errors().empty());
  404. EXPECT_FALSE(parser->results().list.empty());
  405. const auto* first_result = &parser->results().list[0];
  406. EXPECT_FALSE(first_result->manifest.packages.empty());
  407. EXPECT_EQ(1234, first_result->manifest.packages[0].size);
  408. EXPECT_EQ(9007199254740991, first_result->manifest.packages[1].size);
  409. EXPECT_EQ(0, first_result->manifest.packages[2].size);
  410. EXPECT_EQ(0, first_result->manifest.packages[3].size);
  411. EXPECT_EQ(0, first_result->manifest.packages[4].size);
  412. EXPECT_EQ(0, first_result->manifest.packages[5].size);
  413. EXPECT_EQ(0, first_result->manifest.packages[6].size);
  414. EXPECT_EQ(1234, first_result->manifest.packages[7].sizediff);
  415. EXPECT_EQ(9007199254740991, first_result->manifest.packages[8].sizediff);
  416. EXPECT_EQ(0, first_result->manifest.packages[9].sizediff);
  417. EXPECT_EQ(0, first_result->manifest.packages[10].sizediff);
  418. EXPECT_EQ(0, first_result->manifest.packages[11].sizediff);
  419. EXPECT_EQ(0, first_result->manifest.packages[12].sizediff);
  420. }
  421. {
  422. // Parse xml with a <daystart> element.
  423. EXPECT_TRUE(parser->Parse(kJSONWithDaystart));
  424. EXPECT_TRUE(parser->errors().empty());
  425. EXPECT_FALSE(parser->results().list.empty());
  426. EXPECT_EQ(parser->results().daystart_elapsed_seconds, 456);
  427. }
  428. {
  429. // Parse a no-update response.
  430. EXPECT_TRUE(parser->Parse(kJSONNoUpdate));
  431. EXPECT_TRUE(parser->errors().empty());
  432. EXPECT_FALSE(parser->results().list.empty());
  433. const auto* first_result = &parser->results().list[0];
  434. EXPECT_STREQ("noupdate", first_result->status.c_str());
  435. EXPECT_EQ(first_result->extension_id, "12345");
  436. EXPECT_EQ(first_result->manifest.version, "");
  437. }
  438. {
  439. // Parse xml with one error and one success <app> tag.
  440. EXPECT_TRUE(parser->Parse(kJSONTwoAppsOneError));
  441. EXPECT_TRUE(parser->errors().empty());
  442. EXPECT_EQ(2u, parser->results().list.size());
  443. const auto* first_result = &parser->results().list[0];
  444. EXPECT_EQ(first_result->extension_id, "aaaaaaaa");
  445. EXPECT_STREQ("error-unknownApplication", first_result->status.c_str());
  446. EXPECT_TRUE(first_result->manifest.version.empty());
  447. const auto* second_result = &parser->results().list[1];
  448. EXPECT_EQ(second_result->extension_id, "bbbbbbbb");
  449. EXPECT_STREQ("ok", second_result->status.c_str());
  450. EXPECT_EQ("1.2.3.4", second_result->manifest.version);
  451. }
  452. {
  453. // Parse xml with two apps setting the cohort info.
  454. EXPECT_TRUE(parser->Parse(kJSONTwoAppsSetCohort));
  455. EXPECT_TRUE(parser->errors().empty());
  456. EXPECT_EQ(2u, parser->results().list.size());
  457. const auto* first_result = &parser->results().list[0];
  458. EXPECT_EQ(first_result->extension_id, "aaaaaaaa");
  459. EXPECT_NE(first_result->cohort_attrs.find("cohort"),
  460. first_result->cohort_attrs.end());
  461. EXPECT_EQ(first_result->cohort_attrs.find("cohort")->second, "1:2q3/");
  462. EXPECT_EQ(first_result->cohort_attrs.find("cohortname"),
  463. first_result->cohort_attrs.end());
  464. EXPECT_EQ(first_result->cohort_attrs.find("cohorthint"),
  465. first_result->cohort_attrs.end());
  466. const auto* second_result = &parser->results().list[1];
  467. EXPECT_EQ(second_result->extension_id, "bbbbbbbb");
  468. EXPECT_NE(second_result->cohort_attrs.find("cohort"),
  469. second_result->cohort_attrs.end());
  470. EXPECT_EQ(second_result->cohort_attrs.find("cohort")->second, "1:33z@0.33");
  471. EXPECT_NE(second_result->cohort_attrs.find("cohortname"),
  472. second_result->cohort_attrs.end());
  473. EXPECT_EQ(second_result->cohort_attrs.find("cohortname")->second, "cname");
  474. EXPECT_EQ(second_result->cohort_attrs.find("cohorthint"),
  475. second_result->cohort_attrs.end());
  476. }
  477. {
  478. EXPECT_TRUE(parser->Parse(kJSONUpdateCheckStatusOkWithRunAction));
  479. EXPECT_TRUE(parser->errors().empty());
  480. EXPECT_FALSE(parser->results().list.empty());
  481. const auto* first_result = &parser->results().list[0];
  482. EXPECT_STREQ("ok", first_result->status.c_str());
  483. EXPECT_EQ(first_result->extension_id, "12345");
  484. EXPECT_STREQ("this", first_result->action_run.c_str());
  485. }
  486. {
  487. EXPECT_TRUE(parser->Parse(kJSONUpdateCheckStatusNoUpdateWithRunAction));
  488. EXPECT_TRUE(parser->errors().empty());
  489. EXPECT_FALSE(parser->results().list.empty());
  490. const auto* first_result = &parser->results().list[0];
  491. EXPECT_STREQ("noupdate", first_result->status.c_str());
  492. EXPECT_EQ(first_result->extension_id, "12345");
  493. EXPECT_STREQ("this", first_result->action_run.c_str());
  494. }
  495. {
  496. EXPECT_TRUE(parser->Parse(kJSONUpdateCheckStatusErrorWithRunAction));
  497. EXPECT_FALSE(parser->errors().empty());
  498. EXPECT_TRUE(parser->results().list.empty());
  499. }
  500. {
  501. EXPECT_TRUE(parser->Parse(kJSONAppsStatusError));
  502. EXPECT_STREQ("Unknown app status", parser->errors().c_str());
  503. EXPECT_EQ(3u, parser->results().list.size());
  504. const auto* first_result = &parser->results().list[0];
  505. EXPECT_EQ(first_result->extension_id, "aaaaaaaa");
  506. EXPECT_STREQ("error-unknownApplication", first_result->status.c_str());
  507. EXPECT_TRUE(first_result->manifest.version.empty());
  508. const auto* second_result = &parser->results().list[1];
  509. EXPECT_EQ(second_result->extension_id, "bbbbbbbb");
  510. EXPECT_STREQ("restricted", second_result->status.c_str());
  511. EXPECT_TRUE(second_result->manifest.version.empty());
  512. const auto* third_result = &parser->results().list[2];
  513. EXPECT_EQ(third_result->extension_id, "cccccccc");
  514. EXPECT_STREQ("error-invalidAppId", third_result->status.c_str());
  515. EXPECT_TRUE(third_result->manifest.version.empty());
  516. }
  517. {
  518. EXPECT_TRUE(parser->Parse(kJSONManifestRun));
  519. EXPECT_TRUE(parser->errors().empty());
  520. EXPECT_EQ(1u, parser->results().list.size());
  521. const auto& result = parser->results().list[0];
  522. EXPECT_STREQ("UpdaterSetup.exe", result.manifest.run.c_str());
  523. EXPECT_STREQ("--arg1 --arg2", result.manifest.arguments.c_str());
  524. ASSERT_EQ(1u, result.data.size());
  525. EXPECT_STREQ("ok", result.data[0].status.c_str());
  526. EXPECT_STREQ("install", result.data[0].name.c_str());
  527. EXPECT_STREQ("foobar_install_data_index",
  528. result.data[0].install_data_index.c_str());
  529. EXPECT_STREQ("sampledata", result.data[0].text.c_str());
  530. }
  531. }
  532. TEST(UpdateClientProtocolParserJSONTest, ParseAttrs) {
  533. const auto parser = std::make_unique<ProtocolParserJSON>();
  534. { // No custom attrs in kJSONManifestRun
  535. EXPECT_TRUE(parser->Parse(kJSONManifestRun));
  536. EXPECT_TRUE(parser->errors().empty());
  537. EXPECT_EQ(1u, parser->results().list.size());
  538. const auto& result = parser->results().list[0];
  539. EXPECT_EQ(0u, result.custom_attributes.size());
  540. }
  541. { // Two custom attrs in kJSONCustomAttributes
  542. EXPECT_TRUE(parser->Parse(kJSONCustomAttributes));
  543. EXPECT_TRUE(parser->errors().empty());
  544. EXPECT_EQ(1u, parser->results().list.size());
  545. const auto& result = parser->results().list[0];
  546. EXPECT_EQ(2u, result.custom_attributes.size());
  547. EXPECT_EQ("example_value1", result.custom_attributes.at("_example1"));
  548. EXPECT_EQ("example_value2", result.custom_attributes.at("_example2"));
  549. }
  550. }
  551. } // namespace update_client