host_backend_delegate_impl_unittest.cc 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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 "ash/services/multidevice_setup/host_backend_delegate_impl.h"
  5. #include <memory>
  6. #include "ash/components/multidevice/remote_device_test_util.h"
  7. #include "ash/components/multidevice/software_feature.h"
  8. #include "ash/components/multidevice/software_feature_state.h"
  9. #include "ash/constants/ash_features.h"
  10. #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
  11. #include "ash/services/multidevice_setup/fake_eligible_host_devices_provider.h"
  12. #include "ash/services/multidevice_setup/fake_host_backend_delegate.h"
  13. #include "base/containers/flat_map.h"
  14. #include "base/test/scoped_feature_list.h"
  15. #include "base/timer/mock_timer.h"
  16. #include "base/unguessable_token.h"
  17. #include "components/sync_preferences/testing_pref_service_syncable.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. #include "third_party/abseil-cpp/absl/types/optional.h"
  20. namespace ash {
  21. namespace multidevice_setup {
  22. namespace {
  23. const char kPendingRequestHostIdPrefName[] =
  24. "multidevice_setup.pending_request_host_id";
  25. const char kPendingRemovalOfCurrentHost[] = "pendingRemovalOfCurrentHost";
  26. const char kNoPendingRequest[] = "";
  27. const size_t kNumTestDevices = 4;
  28. } // namespace
  29. class MultiDeviceSetupHostBackendDelegateImplTest
  30. : public ::testing::TestWithParam<bool> {
  31. public:
  32. MultiDeviceSetupHostBackendDelegateImplTest(
  33. const MultiDeviceSetupHostBackendDelegateImplTest&) = delete;
  34. MultiDeviceSetupHostBackendDelegateImplTest& operator=(
  35. const MultiDeviceSetupHostBackendDelegateImplTest&) = delete;
  36. protected:
  37. MultiDeviceSetupHostBackendDelegateImplTest()
  38. : test_devices_(
  39. multidevice::CreateRemoteDeviceRefListForTest(kNumTestDevices)) {}
  40. ~MultiDeviceSetupHostBackendDelegateImplTest() override = default;
  41. // testing::Test:
  42. void SetUp() override {
  43. SetFeatureFlags(GetParam() /* use_v1_devicesync */);
  44. // Tests are run once to simulate when v1 DeviceSync is enabled and once to
  45. // simulate when it is disabled, leaving only v2 DeviceSync operational. In
  46. // the former case, only public keys are needed, and in the latter case,
  47. // only Instance IDs are needed.
  48. for (multidevice::RemoteDeviceRef device : test_devices_) {
  49. if (features::ShouldUseV1DeviceSync())
  50. GetMutableRemoteDevice(device)->instance_id.clear();
  51. else
  52. GetMutableRemoteDevice(device)->public_key.clear();
  53. }
  54. fake_eligible_host_devices_provider_ =
  55. std::make_unique<FakeEligibleHostDevicesProvider>();
  56. fake_eligible_host_devices_provider_->set_eligible_host_devices(
  57. test_devices_);
  58. test_pref_service_ =
  59. std::make_unique<sync_preferences::TestingPrefServiceSyncable>();
  60. HostBackendDelegateImpl::RegisterPrefs(test_pref_service_->registry());
  61. fake_device_sync_client_ =
  62. std::make_unique<device_sync::FakeDeviceSyncClient>();
  63. fake_device_sync_client_->set_synced_devices(test_devices_);
  64. }
  65. void TearDown() override {
  66. if (delegate_)
  67. delegate_->RemoveObserver(observer_.get());
  68. }
  69. void CreateDelegate(
  70. const absl::optional<multidevice::RemoteDeviceRef>& initial_host,
  71. const std::string& initial_pending_host_request = kNoPendingRequest) {
  72. SetHostInDeviceSyncClient(initial_host);
  73. test_pref_service_->SetString(kPendingRequestHostIdPrefName,
  74. initial_pending_host_request);
  75. auto mock_timer = std::make_unique<base::MockOneShotTimer>();
  76. mock_timer_ = mock_timer.get();
  77. delegate_ = HostBackendDelegateImpl::Factory::Create(
  78. fake_eligible_host_devices_provider_.get(), test_pref_service_.get(),
  79. fake_device_sync_client_.get(), std::move(mock_timer));
  80. EXPECT_EQ(initial_host, delegate_->GetMultiDeviceHostFromBackend());
  81. observer_ = std::make_unique<FakeHostBackendDelegateObserver>();
  82. delegate_->AddObserver(observer_.get());
  83. }
  84. int GetSetHostNetworkRequestCallbackQueueSize() {
  85. return features::ShouldUseV1DeviceSync()
  86. ? fake_device_sync_client_
  87. ->GetSetSoftwareFeatureStateInputsQueueSize()
  88. : fake_device_sync_client_->GetSetFeatureStatusInputsQueueSize();
  89. }
  90. void InvokePendingSetHostNetworkRequestCallback(
  91. device_sync::mojom::NetworkRequestResult result_code,
  92. bool expected_to_notify_observer_and_start_retry_timer) {
  93. size_t num_failure_events_before_call =
  94. observer_->num_failed_backend_requests();
  95. if (features::ShouldUseV1DeviceSync()) {
  96. fake_device_sync_client_->InvokePendingSetSoftwareFeatureStateCallback(
  97. result_code);
  98. } else {
  99. fake_device_sync_client_->InvokePendingSetFeatureStatusCallback(
  100. result_code);
  101. }
  102. if (expected_to_notify_observer_and_start_retry_timer) {
  103. EXPECT_EQ(num_failure_events_before_call + 1u,
  104. observer_->num_failed_backend_requests());
  105. } else {
  106. EXPECT_EQ(num_failure_events_before_call,
  107. observer_->num_failed_backend_requests());
  108. }
  109. EXPECT_EQ(expected_to_notify_observer_and_start_retry_timer,
  110. mock_timer_->IsRunning());
  111. }
  112. void SimulateNewHostDevicesSynced(
  113. const absl::optional<multidevice::RemoteDeviceRef>&
  114. host_device_after_sync,
  115. bool expected_to_fulfill_pending_request) {
  116. absl::optional<multidevice::RemoteDeviceRef> host_device_before_call =
  117. delegate_->GetMultiDeviceHostFromBackend();
  118. bool host_changed = host_device_before_call != host_device_after_sync;
  119. size_t num_host_change_events_before_call =
  120. observer_->num_changes_on_backend();
  121. size_t num_pending_host_request_change_events_before_call =
  122. observer_->num_pending_host_request_changes();
  123. SetHostInDeviceSyncClient(host_device_after_sync);
  124. fake_device_sync_client_->NotifyNewDevicesSynced();
  125. if (host_changed) {
  126. EXPECT_EQ(num_host_change_events_before_call + 1u,
  127. observer_->num_changes_on_backend());
  128. } else {
  129. EXPECT_EQ(num_host_change_events_before_call,
  130. observer_->num_changes_on_backend());
  131. }
  132. if (expected_to_fulfill_pending_request) {
  133. EXPECT_FALSE(delegate_->HasPendingHostRequest());
  134. // Expected to change from a pending request to no request.
  135. EXPECT_EQ(num_pending_host_request_change_events_before_call + 1u,
  136. observer_->num_pending_host_request_changes());
  137. } else {
  138. EXPECT_EQ(num_pending_host_request_change_events_before_call,
  139. observer_->num_pending_host_request_changes());
  140. }
  141. }
  142. void AttemptToSetMultiDeviceHostOnBackend(
  143. const absl::optional<multidevice::RemoteDeviceRef>& host_device) {
  144. absl::optional<multidevice::RemoteDeviceRef> host_before_call =
  145. delegate_->GetMultiDeviceHostFromBackend();
  146. bool attempting_to_set_host_which_already_exists =
  147. host_device == host_before_call;
  148. size_t num_pending_host_request_change_events_before_call =
  149. observer_->num_pending_host_request_changes();
  150. bool was_request_for_same_device_as_pending_request =
  151. delegate_->HasPendingHostRequest() &&
  152. delegate_->GetPendingHostRequest() == host_device;
  153. delegate_->AttemptToSetMultiDeviceHostOnBackend(host_device);
  154. // A new attempt means that any previous retry attempts should have been
  155. // canceled.
  156. EXPECT_FALSE(mock_timer_->IsRunning());
  157. if (attempting_to_set_host_which_already_exists) {
  158. EXPECT_FALSE(delegate_->HasPendingHostRequest());
  159. return;
  160. }
  161. EXPECT_EQ(host_device, delegate_->GetPendingHostRequest());
  162. if (was_request_for_same_device_as_pending_request) {
  163. EXPECT_EQ(num_pending_host_request_change_events_before_call,
  164. observer_->num_pending_host_request_changes());
  165. } else {
  166. EXPECT_EQ(num_pending_host_request_change_events_before_call + 1u,
  167. observer_->num_pending_host_request_changes());
  168. }
  169. // Verify that the correct parameters were passed to
  170. // SetSoftwareFeatureState() or SetFeatureStatus().
  171. if (host_device) {
  172. VerifyLatestSetHostNetworkRequest(*host_device, true /* should_enable */);
  173. } else {
  174. ASSERT_TRUE(host_before_call);
  175. VerifyLatestSetHostNetworkRequest(*host_before_call,
  176. false /* should_enable */);
  177. }
  178. }
  179. void SetHostInDeviceSyncClient(
  180. const absl::optional<multidevice::RemoteDeviceRef>& host_device) {
  181. for (const auto& remote_device : test_devices_) {
  182. bool should_be_host =
  183. host_device != absl::nullopt &&
  184. ((!remote_device.instance_id().empty() &&
  185. host_device->instance_id() == remote_device.instance_id()) ||
  186. (!remote_device.GetDeviceId().empty() &&
  187. host_device->GetDeviceId() == remote_device.GetDeviceId()));
  188. GetMutableRemoteDevice(remote_device)
  189. ->software_features
  190. [multidevice::SoftwareFeature::kBetterTogetherHost] =
  191. should_be_host ? multidevice::SoftwareFeatureState::kEnabled
  192. : multidevice::SoftwareFeatureState::kSupported;
  193. }
  194. }
  195. FakeEligibleHostDevicesProvider* fake_eligible_host_devices_provider() {
  196. return fake_eligible_host_devices_provider_.get();
  197. }
  198. device_sync::FakeDeviceSyncClient* fake_device_sync_client() {
  199. return fake_device_sync_client_.get();
  200. }
  201. FakeHostBackendDelegateObserver* observer() { return observer_.get(); }
  202. base::MockOneShotTimer* mock_timer() { return mock_timer_; }
  203. HostBackendDelegate* delegate() { return delegate_.get(); }
  204. const multidevice::RemoteDeviceRefList& test_devices() const {
  205. return test_devices_;
  206. }
  207. private:
  208. void SetFeatureFlags(bool use_v1_devicesync) {
  209. std::vector<base::Feature> enabled_features;
  210. std::vector<base::Feature> disabled_features;
  211. // These flags have no direct effect of on the host backend delegate;
  212. // however, v2 Enrollment and DeviceSync must be enabled before v1
  213. // DeviceSync can be disabled.
  214. enabled_features.push_back(chromeos::features::kCryptAuthV2Enrollment);
  215. enabled_features.push_back(chromeos::features::kCryptAuthV2DeviceSync);
  216. if (use_v1_devicesync) {
  217. disabled_features.push_back(
  218. chromeos::features::kDisableCryptAuthV1DeviceSync);
  219. } else {
  220. enabled_features.push_back(
  221. chromeos::features::kDisableCryptAuthV1DeviceSync);
  222. }
  223. scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
  224. }
  225. void VerifyLatestSetHostNetworkRequest(
  226. const multidevice::RemoteDeviceRef expected_host,
  227. bool expected_should_enable) {
  228. // Verify inputs to SetSoftwareFeatureState().
  229. if (features::ShouldUseV1DeviceSync()) {
  230. ASSERT_FALSE(
  231. fake_device_sync_client_->set_software_feature_state_inputs_queue()
  232. .empty());
  233. const device_sync::FakeDeviceSyncClient::SetSoftwareFeatureStateInputs&
  234. inputs = fake_device_sync_client_
  235. ->set_software_feature_state_inputs_queue()
  236. .back();
  237. EXPECT_EQ(expected_host.public_key(), inputs.public_key);
  238. EXPECT_EQ(multidevice::SoftwareFeature::kBetterTogetherHost,
  239. inputs.software_feature);
  240. EXPECT_EQ(expected_should_enable, inputs.enabled);
  241. EXPECT_EQ(expected_should_enable, inputs.is_exclusive);
  242. return;
  243. }
  244. // Verify inputs to SetFeatureStatus().
  245. ASSERT_FALSE(
  246. fake_device_sync_client_->set_feature_status_inputs_queue().empty());
  247. const device_sync::FakeDeviceSyncClient::SetFeatureStatusInputs& inputs =
  248. fake_device_sync_client_->set_feature_status_inputs_queue().back();
  249. EXPECT_EQ(expected_host.instance_id(), inputs.device_instance_id);
  250. EXPECT_EQ(multidevice::SoftwareFeature::kBetterTogetherHost,
  251. inputs.feature);
  252. EXPECT_EQ(expected_should_enable
  253. ? device_sync::FeatureStatusChange::kEnableExclusively
  254. : device_sync::FeatureStatusChange::kDisable,
  255. inputs.status_change);
  256. }
  257. multidevice::RemoteDeviceRefList test_devices_;
  258. std::unique_ptr<FakeEligibleHostDevicesProvider>
  259. fake_eligible_host_devices_provider_;
  260. std::unique_ptr<sync_preferences::TestingPrefServiceSyncable>
  261. test_pref_service_;
  262. std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
  263. base::MockOneShotTimer* mock_timer_;
  264. std::unique_ptr<FakeHostBackendDelegateObserver> observer_;
  265. std::unique_ptr<HostBackendDelegate> delegate_;
  266. base::test::ScopedFeatureList scoped_feature_list_;
  267. };
  268. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest, Success) {
  269. CreateDelegate(absl::nullopt /* initial_host */);
  270. // Set device 0.
  271. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  272. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  273. InvokePendingSetHostNetworkRequestCallback(
  274. device_sync::mojom::NetworkRequestResult::kSuccess,
  275. false /* expected_to_notify_observer_and_start_retry_timer */);
  276. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  277. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  278. SimulateNewHostDevicesSynced(test_devices()[0] /* host_device_after_sync */,
  279. true /* expected_to_fulfill_pending_request */);
  280. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  281. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  282. // Remove device 0 such that there is no longer a host.
  283. AttemptToSetMultiDeviceHostOnBackend(absl::nullopt);
  284. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  285. InvokePendingSetHostNetworkRequestCallback(
  286. device_sync::mojom::NetworkRequestResult::kSuccess,
  287. false /* expected_to_notify_observer_and_start_retry_timer */);
  288. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  289. EXPECT_EQ(absl::nullopt, delegate()->GetPendingHostRequest());
  290. SimulateNewHostDevicesSynced(absl::nullopt /* host_device_after_sync */,
  291. true /* expected_to_fulfill_pending_request */);
  292. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  293. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  294. // Set device 1.
  295. AttemptToSetMultiDeviceHostOnBackend(test_devices()[1]);
  296. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  297. InvokePendingSetHostNetworkRequestCallback(
  298. device_sync::mojom::NetworkRequestResult::kSuccess,
  299. false /* expected_to_notify_observer_and_start_retry_timer */);
  300. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  301. EXPECT_EQ(test_devices()[1], delegate()->GetPendingHostRequest());
  302. SimulateNewHostDevicesSynced(test_devices()[1] /* host_device_after_sync */,
  303. true /* expected_to_fulfill_pending_request */);
  304. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  305. EXPECT_EQ(test_devices()[1], delegate()->GetMultiDeviceHostFromBackend());
  306. }
  307. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest, Failure) {
  308. CreateDelegate(absl::nullopt /* initial_host */);
  309. // Attempt to set device 0, but fail.
  310. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  311. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  312. InvokePendingSetHostNetworkRequestCallback(
  313. device_sync::mojom::NetworkRequestResult::kOffline,
  314. true /* expected_to_notify_observer_and_start_retry_timer */);
  315. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  316. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  317. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  318. // A retry should have been scheduled, so fire the timer to start the retry.
  319. mock_timer()->Fire();
  320. // Simulate another failure.
  321. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  322. InvokePendingSetHostNetworkRequestCallback(
  323. device_sync::mojom::NetworkRequestResult::kOffline,
  324. true /* expected_to_notify_observer_and_start_retry_timer */);
  325. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  326. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  327. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  328. // Attempt to set device 1, but fail.
  329. AttemptToSetMultiDeviceHostOnBackend(test_devices()[1]);
  330. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  331. InvokePendingSetHostNetworkRequestCallback(
  332. device_sync::mojom::NetworkRequestResult::kOffline,
  333. true /* expected_to_notify_observer_and_start_retry_timer */);
  334. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  335. EXPECT_EQ(test_devices()[1], delegate()->GetPendingHostRequest());
  336. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  337. }
  338. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  339. StartWithDevice_SimultaneousRequests) {
  340. // Start with device 0 as the active host.
  341. CreateDelegate(test_devices()[0] /* initial_host */);
  342. // Attempt to set device 1, but do not invoke the callback yet.
  343. AttemptToSetMultiDeviceHostOnBackend(test_devices()[1]);
  344. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  345. EXPECT_EQ(test_devices()[1], delegate()->GetPendingHostRequest());
  346. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  347. // Attempt to set device 2, but do not invoke device 1's callback yet.
  348. AttemptToSetMultiDeviceHostOnBackend(test_devices()[2]);
  349. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  350. EXPECT_EQ(test_devices()[2], delegate()->GetPendingHostRequest());
  351. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  352. // Attempt to set device 3.
  353. AttemptToSetMultiDeviceHostOnBackend(test_devices()[3]);
  354. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  355. EXPECT_EQ(test_devices()[3], delegate()->GetPendingHostRequest());
  356. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  357. // Note: Below, we assume that the feature setting requests are processed in
  358. // the order they are called. This is an assumption made in the
  359. // HostBackendDelegate implementation.
  360. // Fire the callback for device 1, but have it fail. This is not expected to
  361. // notify the observer or start the retry timer, since the failure was for
  362. // device 1's request and device 3 is the pending host request.
  363. EXPECT_EQ(3, GetSetHostNetworkRequestCallbackQueueSize());
  364. InvokePendingSetHostNetworkRequestCallback(
  365. device_sync::mojom::NetworkRequestResult::kOffline,
  366. false /* expected_to_notify_observer_and_start_retry_timer */);
  367. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  368. EXPECT_EQ(test_devices()[3], delegate()->GetPendingHostRequest());
  369. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  370. // Fire the callback for device 2, and have it succeed. This should affect the
  371. // value of GetMultiDeviceHostFromBackend(), but there should still be a
  372. // pending request for device 3.
  373. EXPECT_EQ(2, GetSetHostNetworkRequestCallbackQueueSize());
  374. InvokePendingSetHostNetworkRequestCallback(
  375. device_sync::mojom::NetworkRequestResult::kSuccess,
  376. false /* expected_to_notify_observer_and_start_retry_timer */);
  377. SimulateNewHostDevicesSynced(test_devices()[2] /* host_device_after_sync */,
  378. false /* expected_to_fulfill_pending_request */);
  379. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  380. EXPECT_EQ(test_devices()[3], delegate()->GetPendingHostRequest());
  381. EXPECT_EQ(test_devices()[2], delegate()->GetMultiDeviceHostFromBackend());
  382. // Fire the callback for device 3, and have it succeed.
  383. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  384. InvokePendingSetHostNetworkRequestCallback(
  385. device_sync::mojom::NetworkRequestResult::kSuccess,
  386. false /* expected_to_notify_observer_and_start_retry_timer */);
  387. SimulateNewHostDevicesSynced(test_devices()[3] /* host_device_after_sync */,
  388. true /* expected_to_fulfill_pending_request */);
  389. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  390. EXPECT_EQ(test_devices()[3], delegate()->GetMultiDeviceHostFromBackend());
  391. }
  392. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  393. SimultaneousRequestsToSameDevice) {
  394. CreateDelegate(absl::nullopt /* initial_host */);
  395. // Attempt to set device 0, but do not invoke the callback yet.
  396. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  397. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  398. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  399. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  400. // Attempt to set device 0 again, and still do not invoke the callback.
  401. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  402. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  403. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  404. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  405. // Attempt to set device 0 one more time.
  406. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  407. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  408. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  409. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  410. // Fire the first callback, which should successfully transition the host.
  411. EXPECT_EQ(3, GetSetHostNetworkRequestCallbackQueueSize());
  412. InvokePendingSetHostNetworkRequestCallback(
  413. device_sync::mojom::NetworkRequestResult::kSuccess,
  414. false /* expected_to_notify_observer_and_start_retry_timer */);
  415. SimulateNewHostDevicesSynced(test_devices()[0] /* host_device_after_sync */,
  416. true /* expected_to_fulfill_pending_request */);
  417. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  418. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  419. // Fire the second callback, but have it fail. No state should be affected.
  420. EXPECT_EQ(2, GetSetHostNetworkRequestCallbackQueueSize());
  421. InvokePendingSetHostNetworkRequestCallback(
  422. device_sync::mojom::NetworkRequestResult::kOffline,
  423. false /* expected_to_notify_observer_and_start_retry_timer */);
  424. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  425. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  426. // Fire the third callback, and have it succeed. Still, no state should be
  427. // affected.
  428. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  429. InvokePendingSetHostNetworkRequestCallback(
  430. device_sync::mojom::NetworkRequestResult::kSuccess,
  431. false /* expected_to_notify_observer_and_start_retry_timer */);
  432. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  433. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  434. }
  435. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  436. MultipleRequestsToSameDevice_FirstFail_ThenSucceed) {
  437. CreateDelegate(absl::nullopt /* initial_host */);
  438. // Attempt to set device 0, but fail.
  439. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  440. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  441. InvokePendingSetHostNetworkRequestCallback(
  442. device_sync::mojom::NetworkRequestResult::kOffline,
  443. true /* expected_to_notify_observer_and_start_retry_timer */);
  444. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  445. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  446. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  447. // The retry timer is running; however, instead of relying on that, call
  448. // AttemptToSetMultiDeviceHostOnBackend() again to trigger an immediate retry
  449. // without the timer.
  450. AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  451. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  452. InvokePendingSetHostNetworkRequestCallback(
  453. device_sync::mojom::NetworkRequestResult::kSuccess,
  454. false /* expected_to_notify_observer_and_start_retry_timer */);
  455. EXPECT_TRUE(delegate()->HasPendingHostRequest());
  456. EXPECT_EQ(test_devices()[0], delegate()->GetPendingHostRequest());
  457. SimulateNewHostDevicesSynced(test_devices()[0] /* host_device_after_sync */,
  458. true /* expected_to_fulfill_pending_request */);
  459. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  460. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  461. }
  462. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  463. InitialPendingRequestButNoInitialDevice) {
  464. CreateDelegate(
  465. absl::nullopt /* initial_host */,
  466. features::ShouldUseV1DeviceSync()
  467. ? test_devices()[0].GetDeviceId()
  468. : test_devices()[0].instance_id() /* initial_pending_host_request */);
  469. // The delegate should have started a request as soon as it was created.
  470. // Simulate it succeeding.
  471. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  472. InvokePendingSetHostNetworkRequestCallback(
  473. device_sync::mojom::NetworkRequestResult::kSuccess,
  474. false /* expected_to_notify_observer_and_start_retry_timer */);
  475. SimulateNewHostDevicesSynced(test_devices()[0] /* host_device_after_sync */,
  476. true /* expected_to_fulfill_pending_request */);
  477. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  478. EXPECT_EQ(test_devices()[0], delegate()->GetMultiDeviceHostFromBackend());
  479. }
  480. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  481. InitialDeviceWithPendingRequestToRemoveIt) {
  482. CreateDelegate(
  483. test_devices()[0] /* initial_host */,
  484. kPendingRemovalOfCurrentHost /* initial_pending_host_request */);
  485. // The delegate should have started a request as soon as it was created.
  486. // Simulate it succeeding.
  487. EXPECT_EQ(1, GetSetHostNetworkRequestCallbackQueueSize());
  488. InvokePendingSetHostNetworkRequestCallback(
  489. device_sync::mojom::NetworkRequestResult::kSuccess,
  490. false /* expected_to_notify_observer_and_start_retry_timer */);
  491. SimulateNewHostDevicesSynced(absl::nullopt /* host_device_after_sync */,
  492. true /* expected_to_fulfill_pending_request */);
  493. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  494. EXPECT_EQ(absl::nullopt, delegate()->GetMultiDeviceHostFromBackend());
  495. }
  496. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest, ChangedFromOtherDevice) {
  497. CreateDelegate(absl::nullopt /* initial_host */);
  498. // The device changed from another device (i.e.,
  499. // AttemptToSetMultiDeviceHostOnBackend() was not called).
  500. SimulateNewHostDevicesSynced(test_devices()[0] /* host_device_after_sync */,
  501. false /* expected_to_fulfill_pending_request */);
  502. // One more change.
  503. SimulateNewHostDevicesSynced(test_devices()[1] /* host_device_after_sync */,
  504. false /* expected_to_fulfill_pending_request */);
  505. }
  506. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  507. PendingRequestCanceledIfDeviceToSetNoLongerExists) {
  508. CreateDelegate(absl::nullopt /* initial_host */,
  509. "nonexistentDeviceId" /* initial_pending_host_request */);
  510. // An initial pending host request exists, but it is for a host that is not
  511. // present in the DeviceSyncClient. Thus, the request should be canceled.
  512. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  513. }
  514. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest,
  515. PendingRequestCanceledIfDeviceToRemoveNoLongerExists) {
  516. CreateDelegate(
  517. absl::nullopt /* initial_host */,
  518. kPendingRemovalOfCurrentHost /* initial_pending_host_request */);
  519. // An initial pending host request exists to remove the current host, but
  520. // there actually is no current host. Thus, the request should be canceled.
  521. EXPECT_FALSE(delegate()->HasPendingHostRequest());
  522. }
  523. TEST_P(MultiDeviceSetupHostBackendDelegateImplTest, TryToSetNonEligibleHost) {
  524. // Make all test devices ineligible.
  525. fake_eligible_host_devices_provider()->set_eligible_host_devices(
  526. multidevice::RemoteDeviceRefList());
  527. CreateDelegate(absl::nullopt /* initial_host */);
  528. delegate()->AttemptToSetMultiDeviceHostOnBackend(test_devices()[0]);
  529. EXPECT_EQ(0u, observer()->num_pending_host_request_changes());
  530. }
  531. // Runs tests twice; once with v1 DeviceSync enabled and once with it disabled.
  532. // TODO(https://crbug.com/1019206): Remove when v1 DeviceSync is disabled,
  533. // when all devices should have an Instance ID.
  534. INSTANTIATE_TEST_SUITE_P(All,
  535. MultiDeviceSetupHostBackendDelegateImplTest,
  536. ::testing::Bool());
  537. } // namespace multidevice_setup
  538. } // namespace ash