PageRenderTime 52ms CodeModel.GetById 4ms RepoModel.GetById 0ms app.codeStats 0ms

/chromeos/services/device_sync/cryptauth_feature_status_setter_impl_unittest.cc

http://github.com/chromium/chromium
C++ | 347 lines | 271 code | 59 blank | 17 comment | 2 complexity | a068b804e1db9f4f03775609a5dbfbcc MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  1. // Copyright 2019 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 "chromeos/services/device_sync/cryptauth_feature_status_setter_impl.h"
  5. #include <memory>
  6. #include <string>
  7. #include <utility>
  8. #include "base/containers/queue.h"
  9. #include "base/macros.h"
  10. #include "base/no_destructor.h"
  11. #include "base/optional.h"
  12. #include "base/timer/mock_timer.h"
  13. #include "chromeos/services/device_sync/cryptauth_client.h"
  14. #include "chromeos/services/device_sync/cryptauth_key_bundle.h"
  15. #include "chromeos/services/device_sync/fake_cryptauth_gcm_manager.h"
  16. #include "chromeos/services/device_sync/feature_status_change.h"
  17. #include "chromeos/services/device_sync/mock_cryptauth_client.h"
  18. #include "chromeos/services/device_sync/network_request_error.h"
  19. #include "chromeos/services/device_sync/proto/cryptauth_client_app_metadata.pb.h"
  20. #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
  21. #include "chromeos/services/device_sync/proto/cryptauth_devicesync.pb.h"
  22. #include "chromeos/services/device_sync/proto/cryptauth_v2_test_util.h"
  23. #include "chromeos/services/device_sync/public/cpp/fake_client_app_metadata_provider.h"
  24. #include "testing/gtest/include/gtest/gtest.h"
  25. namespace chromeos {
  26. namespace device_sync {
  27. namespace {
  28. const char kAccessTokenUsed[] = "access token used by CryptAuthClient";
  29. const cryptauthv2::ClientMetadata& GetClientMetadata() {
  30. static const base::NoDestructor<cryptauthv2::ClientMetadata> client_metadata(
  31. [] {
  32. cryptauthv2::ClientMetadata client_metadata;
  33. client_metadata.set_invocation_reason(
  34. cryptauthv2::ClientMetadata::FEATURE_TOGGLED);
  35. return client_metadata;
  36. }());
  37. return *client_metadata;
  38. }
  39. const cryptauthv2::RequestContext& GetRequestContext() {
  40. static const base::NoDestructor<cryptauthv2::RequestContext> request_context(
  41. cryptauthv2::BuildRequestContext(
  42. CryptAuthKeyBundle::KeyBundleNameEnumToString(
  43. CryptAuthKeyBundle::Name::kDeviceSyncBetterTogether),
  44. GetClientMetadata(),
  45. cryptauthv2::GetClientAppMetadataForTest().instance_id(),
  46. cryptauthv2::GetClientAppMetadataForTest().instance_id_token()));
  47. return *request_context;
  48. }
  49. cryptauthv2::BatchSetFeatureStatusesRequest BetterTogetherHostEnabledRequest(
  50. const std::string& device_id) {
  51. cryptauthv2::BatchSetFeatureStatusesRequest request;
  52. request.mutable_context()->CopyFrom(GetRequestContext());
  53. cryptauthv2::DeviceFeatureStatus* device_feature_status =
  54. request.add_device_feature_statuses();
  55. device_feature_status->set_device_id(device_id);
  56. cryptauthv2::DeviceFeatureStatus::FeatureStatus* feature_status =
  57. device_feature_status->add_feature_statuses();
  58. feature_status->set_feature_type(CryptAuthFeatureTypeToString(
  59. CryptAuthFeatureType::kBetterTogetherHostEnabled));
  60. feature_status->set_enabled(true);
  61. feature_status->set_enable_exclusively(false);
  62. return request;
  63. }
  64. cryptauthv2::BatchSetFeatureStatusesRequest
  65. SmartLockHostExclusivelyEnabledRequest(const std::string& device_id) {
  66. cryptauthv2::BatchSetFeatureStatusesRequest request;
  67. request.mutable_context()->CopyFrom(GetRequestContext());
  68. cryptauthv2::DeviceFeatureStatus* device_feature_status =
  69. request.add_device_feature_statuses();
  70. device_feature_status->set_device_id(device_id);
  71. cryptauthv2::DeviceFeatureStatus::FeatureStatus* feature_status =
  72. device_feature_status->add_feature_statuses();
  73. feature_status->set_feature_type(CryptAuthFeatureTypeToString(
  74. CryptAuthFeatureType::kEasyUnlockHostEnabled));
  75. feature_status->set_enabled(true);
  76. feature_status->set_enable_exclusively(true);
  77. return request;
  78. }
  79. cryptauthv2::BatchSetFeatureStatusesRequest InstantTetherClientDisabledRequest(
  80. const std::string& device_id) {
  81. cryptauthv2::BatchSetFeatureStatusesRequest request;
  82. request.mutable_context()->CopyFrom(GetRequestContext());
  83. cryptauthv2::DeviceFeatureStatus* device_feature_status =
  84. request.add_device_feature_statuses();
  85. device_feature_status->set_device_id(device_id);
  86. cryptauthv2::DeviceFeatureStatus::FeatureStatus* feature_status =
  87. device_feature_status->add_feature_statuses();
  88. feature_status->set_feature_type(CryptAuthFeatureTypeToString(
  89. CryptAuthFeatureType::kMagicTetherClientEnabled));
  90. feature_status->set_enabled(false);
  91. feature_status->set_enable_exclusively(false);
  92. return request;
  93. }
  94. } // namespace
  95. class DeviceSyncCryptAuthFeatureStatusSetterImplTest
  96. : public testing::Test,
  97. public MockCryptAuthClientFactory::Observer {
  98. protected:
  99. enum class RequestAction { kSucceed, kFail, kTimeout };
  100. DeviceSyncCryptAuthFeatureStatusSetterImplTest()
  101. : mock_client_factory_(
  102. MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS),
  103. fake_gcm_manager_(cryptauthv2::kTestGcmRegistrationId) {
  104. mock_client_factory_.AddObserver(this);
  105. }
  106. ~DeviceSyncCryptAuthFeatureStatusSetterImplTest() override {
  107. mock_client_factory_.RemoveObserver(this);
  108. }
  109. // testing::Test:
  110. void SetUp() override {
  111. auto mock_timer = std::make_unique<base::MockOneShotTimer>();
  112. mock_timer_ = mock_timer.get();
  113. feature_status_setter_ = CryptAuthFeatureStatusSetterImpl::Factory::Create(
  114. &fake_client_app_metadata_provider_, &mock_client_factory_,
  115. &fake_gcm_manager_, std::move(mock_timer));
  116. }
  117. // MockCryptAuthClientFactory::Observer:
  118. void OnCryptAuthClientCreated(MockCryptAuthClient* client) override {
  119. ON_CALL(*client,
  120. BatchSetFeatureStatuses(testing::_, testing::_, testing::_))
  121. .WillByDefault(
  122. Invoke(this, &DeviceSyncCryptAuthFeatureStatusSetterImplTest::
  123. OnBatchSetFeatureStatuses));
  124. ON_CALL(*client, GetAccessTokenUsed())
  125. .WillByDefault(testing::Return(kAccessTokenUsed));
  126. }
  127. void SetFeatureStatus(const std::string& device_id,
  128. multidevice::SoftwareFeature feature,
  129. FeatureStatusChange status_change) {
  130. feature_status_setter_->SetFeatureStatus(
  131. device_id, feature, status_change,
  132. base::BindOnce(&DeviceSyncCryptAuthFeatureStatusSetterImplTest::
  133. OnSetFeatureStatusSuccess,
  134. base::Unretained(this)),
  135. base::BindOnce(&DeviceSyncCryptAuthFeatureStatusSetterImplTest::
  136. OnSetFeatureStatusFailure,
  137. base::Unretained(this)));
  138. }
  139. void HandleClientAppMetadataRequest(RequestAction request_action) {
  140. ASSERT_FALSE(
  141. fake_client_app_metadata_provider_.metadata_requests().empty());
  142. EXPECT_EQ(cryptauthv2::kTestGcmRegistrationId,
  143. fake_client_app_metadata_provider_.metadata_requests()
  144. .back()
  145. .gcm_registration_id);
  146. switch (request_action) {
  147. case RequestAction::kSucceed:
  148. std::move(fake_client_app_metadata_provider_.metadata_requests()
  149. .back()
  150. .callback)
  151. .Run(cryptauthv2::GetClientAppMetadataForTest());
  152. return;
  153. case RequestAction::kFail:
  154. std::move(fake_client_app_metadata_provider_.metadata_requests()
  155. .back()
  156. .callback)
  157. .Run(base::nullopt /* client_app_metadata */);
  158. return;
  159. case RequestAction::kTimeout:
  160. mock_timer_->Fire();
  161. return;
  162. }
  163. }
  164. void HandleNextBatchSetFeatureStatusesRequest(
  165. const cryptauthv2::BatchSetFeatureStatusesRequest& expected_request,
  166. RequestAction request_action,
  167. base::Optional<NetworkRequestError> error = base::nullopt) {
  168. ASSERT_TRUE(!batch_set_feature_statuses_requests_.empty());
  169. cryptauthv2::BatchSetFeatureStatusesRequest current_request =
  170. std::move(batch_set_feature_statuses_requests_.front());
  171. batch_set_feature_statuses_requests_.pop();
  172. CryptAuthClient::BatchSetFeatureStatusesCallback current_success_callback =
  173. std::move(batch_set_feature_statuses_success_callbacks_.front());
  174. batch_set_feature_statuses_success_callbacks_.pop();
  175. CryptAuthClient::ErrorCallback current_failure_callback =
  176. std::move(batch_set_feature_statuses_failure_callbacks_.front());
  177. batch_set_feature_statuses_failure_callbacks_.pop();
  178. EXPECT_EQ(expected_request.SerializeAsString(),
  179. current_request.SerializeAsString());
  180. switch (request_action) {
  181. case RequestAction::kSucceed:
  182. std::move(current_success_callback)
  183. .Run(cryptauthv2::BatchSetFeatureStatusesResponse());
  184. break;
  185. case RequestAction::kFail:
  186. ASSERT_TRUE(error);
  187. std::move(current_failure_callback).Run(*error);
  188. break;
  189. case RequestAction::kTimeout:
  190. mock_timer_->Fire();
  191. break;
  192. }
  193. }
  194. void VerifyNumberOfClientAppMetadataFetchAttempts(size_t num_attempts) {
  195. EXPECT_EQ(num_attempts,
  196. fake_client_app_metadata_provider_.metadata_requests().size());
  197. }
  198. void VerifyResults(
  199. const std::vector<base::Optional<NetworkRequestError>> expected_results) {
  200. // Verify that all requests were processed.
  201. EXPECT_TRUE(batch_set_feature_statuses_requests_.empty());
  202. EXPECT_TRUE(batch_set_feature_statuses_success_callbacks_.empty());
  203. EXPECT_TRUE(batch_set_feature_statuses_failure_callbacks_.empty());
  204. EXPECT_EQ(expected_results, results_);
  205. }
  206. private:
  207. void OnBatchSetFeatureStatuses(
  208. const cryptauthv2::BatchSetFeatureStatusesRequest& request,
  209. const CryptAuthClient::BatchSetFeatureStatusesCallback& callback,
  210. const CryptAuthClient::ErrorCallback& error_callback) {
  211. batch_set_feature_statuses_requests_.push(request);
  212. batch_set_feature_statuses_success_callbacks_.push(std::move(callback));
  213. batch_set_feature_statuses_failure_callbacks_.push(
  214. std::move(error_callback));
  215. }
  216. void OnSetFeatureStatusSuccess() { results_.push_back(base::nullopt); }
  217. void OnSetFeatureStatusFailure(NetworkRequestError error) {
  218. results_.push_back(error);
  219. }
  220. base::queue<cryptauthv2::BatchSetFeatureStatusesRequest>
  221. batch_set_feature_statuses_requests_;
  222. base::queue<CryptAuthClient::BatchSetFeatureStatusesCallback>
  223. batch_set_feature_statuses_success_callbacks_;
  224. base::queue<CryptAuthClient::ErrorCallback>
  225. batch_set_feature_statuses_failure_callbacks_;
  226. // base::nullopt indicates a success.
  227. std::vector<base::Optional<NetworkRequestError>> results_;
  228. FakeClientAppMetadataProvider fake_client_app_metadata_provider_;
  229. MockCryptAuthClientFactory mock_client_factory_;
  230. FakeCryptAuthGCMManager fake_gcm_manager_;
  231. base::MockOneShotTimer* mock_timer_ = nullptr;
  232. std::unique_ptr<CryptAuthFeatureStatusSetter> feature_status_setter_;
  233. DISALLOW_COPY_AND_ASSIGN(DeviceSyncCryptAuthFeatureStatusSetterImplTest);
  234. };
  235. TEST_F(DeviceSyncCryptAuthFeatureStatusSetterImplTest, Test) {
  236. // Queue up 6 requests before any finish. They should be processed
  237. // sequentially.
  238. SetFeatureStatus("device_id_1",
  239. multidevice::SoftwareFeature::kSmartLockClient,
  240. FeatureStatusChange::kDisable);
  241. SetFeatureStatus("device_id_2",
  242. multidevice::SoftwareFeature::kInstantTetheringHost,
  243. FeatureStatusChange::kEnableNonExclusively);
  244. SetFeatureStatus("device_id_3", multidevice::SoftwareFeature::kSmartLockHost,
  245. FeatureStatusChange::kEnableExclusively);
  246. SetFeatureStatus("device_id_4",
  247. multidevice::SoftwareFeature::kInstantTetheringClient,
  248. FeatureStatusChange::kDisable);
  249. SetFeatureStatus("device_id_5",
  250. multidevice::SoftwareFeature::kInstantTetheringClient,
  251. FeatureStatusChange::kDisable);
  252. SetFeatureStatus("device_id_6",
  253. multidevice::SoftwareFeature::kBetterTogetherHost,
  254. FeatureStatusChange::kEnableNonExclusively);
  255. // base::nullopt indicates a success.
  256. std::vector<base::Optional<NetworkRequestError>> expected_results;
  257. // Timeout waiting for ClientAppMetadata.
  258. HandleClientAppMetadataRequest(RequestAction::kTimeout);
  259. expected_results.push_back(NetworkRequestError::kUnknown);
  260. // Fail ClientAppMetadata fetch.
  261. HandleClientAppMetadataRequest(RequestAction::kFail);
  262. expected_results.push_back(NetworkRequestError::kUnknown);
  263. // Timeout waiting for BatchSetFeatureStatuses.
  264. HandleClientAppMetadataRequest(RequestAction::kSucceed);
  265. HandleNextBatchSetFeatureStatusesRequest(
  266. SmartLockHostExclusivelyEnabledRequest("device_id_3"),
  267. RequestAction::kTimeout);
  268. expected_results.push_back(NetworkRequestError::kUnknown);
  269. // Fail BatchSetFeatureStatuses call with "Bad Request".
  270. HandleNextBatchSetFeatureStatusesRequest(
  271. InstantTetherClientDisabledRequest("device_id_4"), RequestAction::kFail,
  272. NetworkRequestError::kBadRequest);
  273. expected_results.push_back(NetworkRequestError::kBadRequest);
  274. // Succeed disabling InstantTethering client.
  275. HandleNextBatchSetFeatureStatusesRequest(
  276. InstantTetherClientDisabledRequest("device_id_5"),
  277. RequestAction::kSucceed);
  278. expected_results.push_back(base::nullopt);
  279. // Succeed enabling BetterTogether host.
  280. HandleNextBatchSetFeatureStatusesRequest(
  281. BetterTogetherHostEnabledRequest("device_id_6"), RequestAction::kSucceed);
  282. expected_results.push_back(base::nullopt);
  283. // There was 1 timeout, 1 failed attempt, and 1 successful attempt.
  284. VerifyNumberOfClientAppMetadataFetchAttempts(3u);
  285. VerifyResults(expected_results);
  286. }
  287. } // namespace device_sync
  288. } // namespace chromeos