gaia_oauth_client_unittest.cc 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. // Copyright (c) 2012 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. //
  5. // A complete set of unit tests for GaiaOAuthClient.
  6. #include <string>
  7. #include <utility>
  8. #include <vector>
  9. #include "base/bind.h"
  10. #include "base/json/json_reader.h"
  11. #include "base/memory/raw_ptr.h"
  12. #include "base/strings/string_number_conversions.h"
  13. #include "base/test/task_environment.h"
  14. #include "base/time/tick_clock.h"
  15. #include "base/values.h"
  16. #include "google_apis/gaia/gaia_oauth_client.h"
  17. #include "net/base/net_errors.h"
  18. #include "net/http/http_request_headers.h"
  19. #include "net/http/http_status_code.h"
  20. #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  21. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  22. #include "services/network/test/test_url_loader_factory.h"
  23. #include "services/network/test/test_utils.h"
  24. #include "testing/gmock/include/gmock/gmock.h"
  25. #include "testing/gtest/include/gtest/gtest.h"
  26. #include "url/gurl.h"
  27. using ::testing::_;
  28. using ::testing::Eq;
  29. using ::testing::HasSubstr;
  30. using ::testing::Pointee;
  31. using ::testing::SaveArg;
  32. namespace {
  33. // Simulates some number of failures, followed by an optional success.
  34. // Does not distinguish between different URLs.
  35. class ResponseInjector {
  36. public:
  37. explicit ResponseInjector(network::TestURLLoaderFactory* url_loader_factory)
  38. : url_loader_factory_(url_loader_factory),
  39. response_code_(net::HTTP_OK),
  40. complete_immediately_(true),
  41. current_failure_count_(0),
  42. max_failure_count_(0) {
  43. url_loader_factory->SetInterceptor(
  44. base::BindRepeating(&ResponseInjector::AdjustResponseBasedOnSettings,
  45. base::Unretained(this)));
  46. }
  47. ResponseInjector(const ResponseInjector&) = delete;
  48. ResponseInjector& operator=(const ResponseInjector&) = delete;
  49. ~ResponseInjector() {
  50. url_loader_factory_->SetInterceptor(
  51. base::BindRepeating([](const network::ResourceRequest& request) {
  52. ADD_FAILURE() << "Unexpected fetch of:" << request.url;
  53. }));
  54. }
  55. void AdjustResponseBasedOnSettings(const network::ResourceRequest& request) {
  56. url_loader_factory_->ClearResponses();
  57. DCHECK(pending_url_.is_empty());
  58. pending_url_ = request.url;
  59. if (complete_immediately_) {
  60. Finish();
  61. }
  62. }
  63. void Finish() {
  64. net::HttpStatusCode response_code = response_code_;
  65. if (response_code_ != net::HTTP_OK && (max_failure_count_ != -1) &&
  66. (current_failure_count_ == max_failure_count_))
  67. response_code = net::HTTP_OK;
  68. if (response_code != net::HTTP_OK)
  69. ++current_failure_count_;
  70. url_loader_factory_->AddResponse(pending_url_.spec(), results_,
  71. response_code);
  72. pending_url_ = GURL();
  73. }
  74. std::string GetUploadData() {
  75. const std::vector<network::TestURLLoaderFactory::PendingRequest>& pending =
  76. *url_loader_factory_->pending_requests();
  77. if (pending.size() == 1) {
  78. return network::GetUploadData(pending[0].request);
  79. } else {
  80. ADD_FAILURE() << "Unexpected state in GetUploadData";
  81. return "";
  82. }
  83. }
  84. const net::HttpRequestHeaders GetRequestHeaders() {
  85. const std::vector<network::TestURLLoaderFactory::PendingRequest>& pending =
  86. *url_loader_factory_->pending_requests();
  87. if (pending.size() == 1) {
  88. return pending[0].request.headers;
  89. } else {
  90. ADD_FAILURE() << "Unexpected state in GetRequestHeaders";
  91. return {};
  92. }
  93. }
  94. void set_response_code(int response_code) {
  95. response_code_ = static_cast<net::HttpStatusCode>(response_code);
  96. }
  97. void set_max_failure_count(int count) {
  98. max_failure_count_ = count;
  99. }
  100. void set_results(const std::string& results) {
  101. results_ = results;
  102. }
  103. void set_complete_immediately(bool complete_immediately) {
  104. complete_immediately_ = complete_immediately;
  105. }
  106. private:
  107. raw_ptr<network::TestURLLoaderFactory> url_loader_factory_;
  108. GURL pending_url_;
  109. net::HttpStatusCode response_code_;
  110. bool complete_immediately_;
  111. int current_failure_count_;
  112. int max_failure_count_;
  113. std::string results_;
  114. };
  115. const std::string kTestAccessToken = "1/fFAGRNJru1FTz70BzhT3Zg";
  116. const std::string kTestAccessTokenHandle = "1/kjhH87dfgkj87Hhj5KJkjZ";
  117. const std::string kTestRefreshToken =
  118. "1/6BMfW9j53gdGImsixUH6kU5RsR4zwI9lUVX-tqf8JXQ";
  119. const std::string kTestUserEmail = "a_user@gmail.com";
  120. const std::string kTestUserId = "8675309";
  121. const int kTestExpiresIn = 3920;
  122. const std::string kDummyGetTokensResult =
  123. "{\"access_token\":\"" + kTestAccessToken + "\","
  124. "\"expires_in\":" + base::NumberToString(kTestExpiresIn) + ","
  125. "\"refresh_token\":\"" + kTestRefreshToken + "\"}";
  126. const std::string kDummyRefreshTokenResult =
  127. "{\"access_token\":\"" + kTestAccessToken + "\","
  128. "\"expires_in\":" + base::NumberToString(kTestExpiresIn) + "}";
  129. const std::string kDummyUserInfoResult =
  130. "{\"email\":\"" + kTestUserEmail + "\"}";
  131. const std::string kDummyUserIdResult =
  132. "{\"id\":\"" + kTestUserId + "\"}";
  133. const std::string kDummyFullUserInfoResult =
  134. "{"
  135. "\"family_name\": \"Bar\", "
  136. "\"name\": \"Foo Bar\", "
  137. "\"picture\": \"https://lh4.googleusercontent.com/hash/photo.jpg\", "
  138. "\"locale\": \"en\", "
  139. "\"gender\": \"male\", "
  140. "\"link\": \"https://plus.google.com/+FooBar\", "
  141. "\"given_name\": \"Foo\", "
  142. "\"id\": \"12345678901234567890\""
  143. "}";
  144. const std::string kDummyTokenInfoResult =
  145. "{\"issued_to\": \"1234567890.apps.googleusercontent.com\","
  146. "\"audience\": \"1234567890.apps.googleusercontent.com\","
  147. "\"scope\": \"https://googleapis.com/oauth2/v2/tokeninfo\","
  148. "\"expires_in\":" + base::NumberToString(kTestExpiresIn) + "}";
  149. const std::string kDummyTokenHandleInfoResult =
  150. "{\"audience\": \"1234567890.apps.googleusercontent.com\","
  151. "\"expires_in\":" + base::NumberToString(kTestExpiresIn) + "}";
  152. const std::string kDummyAccountCapabilitiesResult =
  153. "{\"accountCapabilities\": ["
  154. "{\"name\": \"accountcapabilities/111\", \"booleanValue\": false},"
  155. "{\"name\": \"accountcapabilities/222\", \"booleanValue\": true}"
  156. "]}";
  157. } // namespace
  158. namespace gaia {
  159. class MockGaiaOAuthClientDelegate : public gaia::GaiaOAuthClient::Delegate {
  160. public:
  161. MockGaiaOAuthClientDelegate() = default;
  162. MockGaiaOAuthClientDelegate(const MockGaiaOAuthClientDelegate&) = delete;
  163. MockGaiaOAuthClientDelegate& operator=(const MockGaiaOAuthClientDelegate&) =
  164. delete;
  165. MOCK_METHOD3(OnGetTokensResponse,
  166. void(const std::string& refresh_token,
  167. const std::string& access_token,
  168. int expires_in_seconds));
  169. MOCK_METHOD2(OnRefreshTokenResponse,
  170. void(const std::string& access_token, int expires_in_seconds));
  171. MOCK_METHOD1(OnGetUserEmailResponse, void(const std::string& user_email));
  172. MOCK_METHOD1(OnGetUserIdResponse, void(const std::string& user_id));
  173. MOCK_METHOD1(OnGetUserInfoResponse,
  174. void(std::unique_ptr<base::DictionaryValue> user_info));
  175. MOCK_METHOD1(OnGetTokenInfoResponse,
  176. void(std::unique_ptr<base::DictionaryValue> token_info));
  177. MOCK_METHOD1(OnGetAccountCapabilitiesResponse,
  178. void(std::unique_ptr<base::Value> account_capabilities));
  179. MOCK_METHOD0(OnOAuthError, void());
  180. MOCK_METHOD1(OnNetworkError, void(int response_code));
  181. };
  182. class GaiaOAuthClientTest : public testing::Test {
  183. protected:
  184. GaiaOAuthClientTest()
  185. : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  186. void SetUp() override {
  187. client_info_.client_id = "test_client_id";
  188. client_info_.client_secret = "test_client_secret";
  189. client_info_.redirect_uri = "test_redirect_uri";
  190. }
  191. scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory() {
  192. return base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  193. &url_loader_factory_);
  194. }
  195. void FlushNetwork() {
  196. // An event loop spin is required for things to be delivered from
  197. // TestURLLoaderFactory to its clients via mojo pipes. In addition,
  198. // some retries may have back off, so may need to advance (mock) time
  199. // for them to finish, too.
  200. task_environment_.FastForwardUntilNoTasksRemain();
  201. }
  202. protected:
  203. void TestAccountCapabilitiesUploadData(
  204. const std::vector<std::string>& capabilities_names,
  205. const std::string& expected_body) {
  206. ResponseInjector injector(&url_loader_factory_);
  207. injector.set_complete_immediately(false);
  208. MockGaiaOAuthClientDelegate delegate;
  209. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  210. auth.GetAccountCapabilities("some_token", capabilities_names, 1, &delegate);
  211. EXPECT_EQ(injector.GetUploadData(), expected_body);
  212. }
  213. base::test::TaskEnvironment task_environment_;
  214. network::TestURLLoaderFactory url_loader_factory_;
  215. OAuthClientInfo client_info_;
  216. };
  217. TEST_F(GaiaOAuthClientTest, NetworkFailure) {
  218. int response_code = net::HTTP_INTERNAL_SERVER_ERROR;
  219. MockGaiaOAuthClientDelegate delegate;
  220. EXPECT_CALL(delegate, OnNetworkError(response_code))
  221. .Times(1);
  222. ResponseInjector injector(&url_loader_factory_);
  223. injector.set_response_code(response_code);
  224. injector.set_max_failure_count(4);
  225. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  226. auth.GetTokensFromAuthCode(client_info_, "auth_code", 2, &delegate);
  227. FlushNetwork();
  228. }
  229. TEST_F(GaiaOAuthClientTest, NetworkFailureRecover) {
  230. int response_code = net::HTTP_INTERNAL_SERVER_ERROR;
  231. MockGaiaOAuthClientDelegate delegate;
  232. EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken,
  233. kTestExpiresIn)).Times(1);
  234. ResponseInjector injector(&url_loader_factory_);
  235. injector.set_response_code(response_code);
  236. injector.set_max_failure_count(4);
  237. injector.set_results(kDummyGetTokensResult);
  238. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  239. auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
  240. FlushNetwork();
  241. }
  242. TEST_F(GaiaOAuthClientTest, NetworkFailureRecoverBackoff) {
  243. // Make sure long backoffs are expontential.
  244. int response_code = net::HTTP_INTERNAL_SERVER_ERROR;
  245. MockGaiaOAuthClientDelegate delegate;
  246. EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken,
  247. kTestExpiresIn))
  248. .Times(1);
  249. ResponseInjector injector(&url_loader_factory_);
  250. injector.set_response_code(response_code);
  251. injector.set_max_failure_count(21);
  252. injector.set_results(kDummyGetTokensResult);
  253. base::TimeTicks start = task_environment_.GetMockTickClock()->NowTicks();
  254. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  255. auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
  256. FlushNetwork();
  257. // Default params are:
  258. // 40% jitter, 700ms initial, 1.4 exponent, ignore first 2 failures.
  259. // So after 19 retries, delay is at least:
  260. // 0.6 * 700ms * 1.4^(19-2) ~ 128s
  261. // After 20:
  262. // 0.6 * 700ms * 1.4^(20-2) ~ 179s
  263. //
  264. // ... so the whole thing should take at least 307s
  265. EXPECT_GE(task_environment_.GetMockTickClock()->NowTicks() - start,
  266. base::Seconds(307));
  267. }
  268. TEST_F(GaiaOAuthClientTest, OAuthFailure) {
  269. int response_code = net::HTTP_BAD_REQUEST;
  270. MockGaiaOAuthClientDelegate delegate;
  271. EXPECT_CALL(delegate, OnOAuthError()).Times(1);
  272. ResponseInjector injector(&url_loader_factory_);
  273. injector.set_response_code(response_code);
  274. injector.set_max_failure_count(-1);
  275. injector.set_results(kDummyGetTokensResult);
  276. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  277. auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
  278. FlushNetwork();
  279. }
  280. TEST_F(GaiaOAuthClientTest, GetTokensSuccess) {
  281. MockGaiaOAuthClientDelegate delegate;
  282. EXPECT_CALL(delegate, OnGetTokensResponse(kTestRefreshToken, kTestAccessToken,
  283. kTestExpiresIn)).Times(1);
  284. ResponseInjector injector(&url_loader_factory_);
  285. injector.set_results(kDummyGetTokensResult);
  286. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  287. auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &delegate);
  288. FlushNetwork();
  289. }
  290. TEST_F(GaiaOAuthClientTest, GetTokensAfterNetworkFailure) {
  291. int response_code = net::HTTP_INTERNAL_SERVER_ERROR;
  292. MockGaiaOAuthClientDelegate failure_delegate;
  293. EXPECT_CALL(failure_delegate, OnNetworkError(response_code)).Times(1);
  294. MockGaiaOAuthClientDelegate success_delegate;
  295. EXPECT_CALL(success_delegate, OnGetTokensResponse(kTestRefreshToken,
  296. kTestAccessToken, kTestExpiresIn)).Times(1);
  297. ResponseInjector injector(&url_loader_factory_);
  298. injector.set_response_code(response_code);
  299. injector.set_max_failure_count(4);
  300. injector.set_results(kDummyGetTokensResult);
  301. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  302. auth.GetTokensFromAuthCode(client_info_, "auth_code", 2, &failure_delegate);
  303. FlushNetwork();
  304. auth.GetTokensFromAuthCode(client_info_, "auth_code", -1, &success_delegate);
  305. FlushNetwork();
  306. }
  307. TEST_F(GaiaOAuthClientTest, RefreshTokenSuccess) {
  308. MockGaiaOAuthClientDelegate delegate;
  309. EXPECT_CALL(delegate, OnRefreshTokenResponse(kTestAccessToken,
  310. kTestExpiresIn)).Times(1);
  311. ResponseInjector injector(&url_loader_factory_);
  312. injector.set_results(kDummyRefreshTokenResult);
  313. injector.set_complete_immediately(false);
  314. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  315. auth.RefreshToken(client_info_, "refresh_token", std::vector<std::string>(),
  316. -1, &delegate);
  317. EXPECT_THAT(injector.GetUploadData(), Not(HasSubstr("scope")));
  318. injector.Finish();
  319. FlushNetwork();
  320. }
  321. TEST_F(GaiaOAuthClientTest, RefreshTokenDownscopingSuccess) {
  322. MockGaiaOAuthClientDelegate delegate;
  323. EXPECT_CALL(delegate, OnRefreshTokenResponse(kTestAccessToken,
  324. kTestExpiresIn)).Times(1);
  325. ResponseInjector injector(&url_loader_factory_);
  326. injector.set_results(kDummyRefreshTokenResult);
  327. injector.set_complete_immediately(false);
  328. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  329. auth.RefreshToken(client_info_, "refresh_token",
  330. std::vector<std::string>(1, "scope4test"), -1, &delegate);
  331. EXPECT_THAT(injector.GetUploadData(), HasSubstr("&scope=scope4test"));
  332. injector.Finish();
  333. FlushNetwork();
  334. }
  335. TEST_F(GaiaOAuthClientTest, GetUserEmail) {
  336. MockGaiaOAuthClientDelegate delegate;
  337. EXPECT_CALL(delegate, OnGetUserEmailResponse(kTestUserEmail)).Times(1);
  338. ResponseInjector injector(&url_loader_factory_);
  339. injector.set_results(kDummyUserInfoResult);
  340. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  341. auth.GetUserEmail("access_token", 1, &delegate);
  342. FlushNetwork();
  343. }
  344. TEST_F(GaiaOAuthClientTest, GetUserId) {
  345. MockGaiaOAuthClientDelegate delegate;
  346. EXPECT_CALL(delegate, OnGetUserIdResponse(kTestUserId)).Times(1);
  347. ResponseInjector injector(&url_loader_factory_);
  348. injector.set_results(kDummyUserIdResult);
  349. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  350. auth.GetUserId("access_token", 1, &delegate);
  351. FlushNetwork();
  352. }
  353. TEST_F(GaiaOAuthClientTest, GetUserInfo) {
  354. std::unique_ptr<base::DictionaryValue> captured_result;
  355. MockGaiaOAuthClientDelegate delegate;
  356. EXPECT_CALL(delegate, OnGetUserInfoResponse(_))
  357. .WillOnce([&](std::unique_ptr<base::DictionaryValue> result) {
  358. captured_result = std::move(result);
  359. });
  360. ResponseInjector injector(&url_loader_factory_);
  361. injector.set_results(kDummyFullUserInfoResult);
  362. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  363. auth.GetUserInfo("access_token", 1, &delegate);
  364. FlushNetwork();
  365. absl::optional<base::Value> expected_value =
  366. base::JSONReader::Read(kDummyFullUserInfoResult);
  367. DCHECK(expected_value);
  368. ASSERT_TRUE(expected_value->is_dict());
  369. EXPECT_EQ(*expected_value, *captured_result);
  370. }
  371. TEST_F(GaiaOAuthClientTest, GetTokenInfo) {
  372. std::unique_ptr<base::DictionaryValue> captured_result;
  373. MockGaiaOAuthClientDelegate delegate;
  374. EXPECT_CALL(delegate, OnGetTokenInfoResponse(_))
  375. .WillOnce([&](std::unique_ptr<base::DictionaryValue> result) {
  376. captured_result = std::move(result);
  377. });
  378. ResponseInjector injector(&url_loader_factory_);
  379. injector.set_results(kDummyTokenInfoResult);
  380. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  381. auth.GetTokenInfo("some_token", 1, &delegate);
  382. FlushNetwork();
  383. std::string issued_to;
  384. ASSERT_TRUE(captured_result->GetString("issued_to", &issued_to));
  385. ASSERT_EQ("1234567890.apps.googleusercontent.com", issued_to);
  386. }
  387. TEST_F(GaiaOAuthClientTest, GetTokenHandleInfo) {
  388. std::unique_ptr<base::DictionaryValue> captured_result;
  389. MockGaiaOAuthClientDelegate delegate;
  390. EXPECT_CALL(delegate, OnGetTokenInfoResponse(_))
  391. .WillOnce([&](std::unique_ptr<base::DictionaryValue> result) {
  392. captured_result = std::move(result);
  393. });
  394. ResponseInjector injector(&url_loader_factory_);
  395. injector.set_results(kDummyTokenHandleInfoResult);
  396. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  397. auth.GetTokenHandleInfo("some_handle", 1, &delegate);
  398. FlushNetwork();
  399. std::string audience;
  400. ASSERT_TRUE(captured_result->GetString("audience", &audience));
  401. ASSERT_EQ("1234567890.apps.googleusercontent.com", audience);
  402. }
  403. TEST_F(GaiaOAuthClientTest, GetAccountCapabilities) {
  404. std::unique_ptr<base::Value> captured_result;
  405. MockGaiaOAuthClientDelegate delegate;
  406. EXPECT_CALL(delegate, OnGetAccountCapabilitiesResponse(_))
  407. .WillOnce([&](std::unique_ptr<base::Value> result) {
  408. captured_result = std::move(result);
  409. });
  410. ResponseInjector injector(&url_loader_factory_);
  411. injector.set_results(kDummyAccountCapabilitiesResult);
  412. injector.set_complete_immediately(false);
  413. GaiaOAuthClient auth(GetSharedURLLoaderFactory());
  414. auth.GetAccountCapabilities("some_token",
  415. {"capability1", "capability2", "capability3"}, 1,
  416. &delegate);
  417. std::string actual_authorization_header;
  418. EXPECT_TRUE(injector.GetRequestHeaders().GetHeader(
  419. "Authorization", &actual_authorization_header));
  420. EXPECT_EQ(actual_authorization_header, "Bearer some_token");
  421. std::string actual_method_override_header;
  422. EXPECT_TRUE(injector.GetRequestHeaders().GetHeader(
  423. "X-HTTP-Method-Override", &actual_method_override_header));
  424. EXPECT_EQ(actual_method_override_header, "GET");
  425. EXPECT_EQ(injector.GetUploadData(),
  426. "names=capability1&names=capability2&names=capability3");
  427. injector.Finish();
  428. FlushNetwork();
  429. auto capabilities =
  430. captured_result->FindListKey("accountCapabilities")->GetListDeprecated();
  431. ASSERT_EQ(capabilities.size(), 2U);
  432. EXPECT_EQ(*capabilities[0].FindStringKey("name"), "accountcapabilities/111");
  433. EXPECT_FALSE(*capabilities[0].FindBoolKey("booleanValue"));
  434. EXPECT_EQ(*capabilities[1].FindStringKey("name"), "accountcapabilities/222");
  435. EXPECT_TRUE(*capabilities[1].FindBoolKey("booleanValue"));
  436. }
  437. TEST_F(GaiaOAuthClientTest,
  438. GetAccountCapabilities_UploadData_OneCapabilityName) {
  439. TestAccountCapabilitiesUploadData({"capability"},
  440. /*expected_body=*/"names=capability");
  441. }
  442. TEST_F(GaiaOAuthClientTest,
  443. GetAccountCapabilities_UploadData_MultipleCapabilityNames) {
  444. TestAccountCapabilitiesUploadData(
  445. {"capability1", "capability2", "capability3"},
  446. /*expected_body=*/
  447. "names=capability1&names=capability2&names=capability3");
  448. }
  449. } // namespace gaia