eligible_host_devices_provider_impl_unittest.cc 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  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/eligible_host_devices_provider_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/proto/cryptauth_api.pb.h"
  11. #include "ash/services/device_sync/public/cpp/fake_device_sync_client.h"
  12. #include "ash/services/device_sync/public/mojom/device_sync.mojom.h"
  13. #include "base/containers/flat_set.h"
  14. #include "base/test/scoped_feature_list.h"
  15. #include "base/time/time_override.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. namespace ash {
  18. namespace multidevice_setup {
  19. namespace {
  20. const size_t kNumTestDevices = 6;
  21. } // namespace
  22. class MultiDeviceSetupEligibleHostDevicesProviderImplTest
  23. : public ::testing::TestWithParam<std::tuple<bool, bool, bool, bool>> {
  24. public:
  25. MultiDeviceSetupEligibleHostDevicesProviderImplTest(
  26. const MultiDeviceSetupEligibleHostDevicesProviderImplTest&) = delete;
  27. MultiDeviceSetupEligibleHostDevicesProviderImplTest& operator=(
  28. const MultiDeviceSetupEligibleHostDevicesProviderImplTest&) = delete;
  29. protected:
  30. MultiDeviceSetupEligibleHostDevicesProviderImplTest()
  31. : test_devices_(
  32. multidevice::CreateRemoteDeviceRefListForTest(kNumTestDevices)) {}
  33. ~MultiDeviceSetupEligibleHostDevicesProviderImplTest() override = default;
  34. // testing::Test:
  35. void SetUp() override {
  36. std::vector<base::Feature> enabled_features;
  37. std::vector<base::Feature> disabled_features;
  38. use_get_devices_activity_status_ = std::get<0>(GetParam());
  39. use_connectivity_status_ = std::get<1>(GetParam());
  40. always_use_active_eligible_devices_ = std::get<2>(GetParam());
  41. use_last_activity_time_to_dedup_ = std::get<3>(GetParam());
  42. if (use_get_devices_activity_status_) {
  43. enabled_features.push_back(
  44. chromeos::features::kCryptAuthV2DeviceActivityStatus);
  45. } else {
  46. disabled_features.push_back(
  47. chromeos::features::kCryptAuthV2DeviceActivityStatus);
  48. }
  49. if (use_connectivity_status_) {
  50. enabled_features.push_back(
  51. chromeos::features::kCryptAuthV2DeviceActivityStatusUseConnectivity);
  52. } else {
  53. disabled_features.push_back(
  54. chromeos::features::kCryptAuthV2DeviceActivityStatusUseConnectivity);
  55. }
  56. if (always_use_active_eligible_devices_) {
  57. enabled_features.push_back(
  58. chromeos::features::kCryptAuthV2AlwaysUseActiveEligibleHosts);
  59. } else {
  60. disabled_features.push_back(
  61. chromeos::features::kCryptAuthV2AlwaysUseActiveEligibleHosts);
  62. }
  63. if (use_last_activity_time_to_dedup_) {
  64. enabled_features.push_back(
  65. chromeos::features::kCryptAuthV2DedupDeviceLastActivityTime);
  66. } else {
  67. disabled_features.push_back(
  68. chromeos::features::kCryptAuthV2DedupDeviceLastActivityTime);
  69. }
  70. scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
  71. fake_device_sync_client_ =
  72. std::make_unique<device_sync::FakeDeviceSyncClient>();
  73. fake_device_sync_client_->set_synced_devices(test_devices_);
  74. provider_ = EligibleHostDevicesProviderImpl::Factory::Create(
  75. fake_device_sync_client_.get());
  76. }
  77. device_sync::FakeDeviceSyncClient* fake_device_sync_client() {
  78. return fake_device_sync_client_.get();
  79. }
  80. multidevice::RemoteDeviceRefList& test_devices() { return test_devices_; }
  81. EligibleHostDevicesProvider* provider() { return provider_.get(); }
  82. void SetBitsOnTestDevices() {
  83. // Devices 0, 1, 2, and 3 are supported.
  84. GetMutableRemoteDevice(test_devices()[0])
  85. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  86. multidevice::SoftwareFeatureState::kSupported;
  87. GetMutableRemoteDevice(test_devices()[1])
  88. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  89. multidevice::SoftwareFeatureState::kSupported;
  90. GetMutableRemoteDevice(test_devices()[2])
  91. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  92. multidevice::SoftwareFeatureState::kSupported;
  93. GetMutableRemoteDevice(test_devices()[3])
  94. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  95. multidevice::SoftwareFeatureState::kSupported;
  96. // Device 4 is enabled.
  97. GetMutableRemoteDevice(test_devices()[4])
  98. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  99. multidevice::SoftwareFeatureState::kEnabled;
  100. // Device 5 is not supported.
  101. GetMutableRemoteDevice(test_devices()[5])
  102. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  103. multidevice::SoftwareFeatureState::kNotSupported;
  104. }
  105. bool use_get_devices_activity_status() const {
  106. return use_get_devices_activity_status_;
  107. }
  108. bool use_connectivity_status() const { return use_connectivity_status_; }
  109. // When the flags is enabled, GetEligibleHostDevices() is the same as
  110. // GetEligibleActiveHostDevices() without the connectivity status.
  111. bool always_use_active_eligible_devices() const {
  112. return always_use_active_eligible_devices_;
  113. }
  114. // When the flag is enabled, only one of devices with same last_activity_time
  115. // will be kept.
  116. bool use_last_activity_time_to_dedup() const {
  117. return use_last_activity_time_to_dedup_;
  118. }
  119. private:
  120. multidevice::RemoteDeviceRefList test_devices_;
  121. std::unique_ptr<device_sync::FakeDeviceSyncClient> fake_device_sync_client_;
  122. std::unique_ptr<EligibleHostDevicesProvider> provider_;
  123. bool use_get_devices_activity_status_;
  124. bool use_connectivity_status_;
  125. bool always_use_active_eligible_devices_;
  126. bool use_last_activity_time_to_dedup_;
  127. base::test::ScopedFeatureList scoped_feature_list_;
  128. };
  129. TEST_P(MultiDeviceSetupEligibleHostDevicesProviderImplTest, Empty) {
  130. EXPECT_TRUE(provider()->GetEligibleHostDevices().empty());
  131. }
  132. TEST_P(MultiDeviceSetupEligibleHostDevicesProviderImplTest, NoEligibleDevices) {
  133. GetMutableRemoteDevice(test_devices()[0])
  134. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  135. multidevice::SoftwareFeatureState::kNotSupported;
  136. GetMutableRemoteDevice(test_devices()[1])
  137. ->software_features[multidevice::SoftwareFeature::kBetterTogetherHost] =
  138. multidevice::SoftwareFeatureState::kNotSupported;
  139. multidevice::RemoteDeviceRefList devices{test_devices()[0],
  140. test_devices()[1]};
  141. fake_device_sync_client()->set_synced_devices(devices);
  142. fake_device_sync_client()->NotifyNewDevicesSynced();
  143. EXPECT_TRUE(provider()->GetEligibleHostDevices().empty());
  144. }
  145. TEST_P(MultiDeviceSetupEligibleHostDevicesProviderImplTest, Sorting) {
  146. SetBitsOnTestDevices();
  147. GetMutableRemoteDevice(test_devices()[0])->last_update_time_millis = 1;
  148. GetMutableRemoteDevice(test_devices()[1])->last_update_time_millis = 25;
  149. GetMutableRemoteDevice(test_devices()[2])->last_update_time_millis = 10;
  150. GetMutableRemoteDevice(test_devices()[3])->last_update_time_millis = 100;
  151. GetMutableRemoteDevice(test_devices()[4])->last_update_time_millis = 1000;
  152. GetMutableRemoteDevice(test_devices()[5])->last_update_time_millis = 10000;
  153. multidevice::RemoteDeviceRefList devices{
  154. test_devices()[0], test_devices()[1], test_devices()[2],
  155. test_devices()[3], test_devices()[4], test_devices()[5]};
  156. fake_device_sync_client()->set_synced_devices(devices);
  157. fake_device_sync_client()->NotifyNewDevicesSynced();
  158. // Set current time so that no devices are filtered out based on their last
  159. // activity time
  160. base::subtle::ScopedTimeClockOverrides time_now_override(
  161. []() { return base::Time::FromTimeT(20000); }, nullptr, nullptr);
  162. std::vector<device_sync::mojom::DeviceActivityStatusPtr>
  163. device_activity_statuses;
  164. device_activity_statuses.emplace_back(
  165. device_sync::mojom::DeviceActivityStatus::New(
  166. test_devices()[0].instance_id(),
  167. /*last_activity_time=*/base::Time::FromTimeT(50),
  168. cryptauthv2::ConnectivityStatus::ONLINE,
  169. /*last_update_time=*/base::Time::FromTimeT(4)));
  170. device_activity_statuses.emplace_back(
  171. device_sync::mojom::DeviceActivityStatus::New(
  172. test_devices()[1].instance_id(),
  173. /*last_activity_time=*/base::Time::FromTimeT(100),
  174. cryptauthv2::ConnectivityStatus::OFFLINE,
  175. /*last_update_time=*/base::Time::FromTimeT(2)));
  176. device_activity_statuses.emplace_back(
  177. device_sync::mojom::DeviceActivityStatus::New(
  178. test_devices()[2].instance_id(),
  179. /*last_activity_time=*/base::Time::FromTimeT(200),
  180. cryptauthv2::ConnectivityStatus::ONLINE,
  181. /*last_update_time=*/base::Time::FromTimeT(1)));
  182. device_activity_statuses.emplace_back(
  183. device_sync::mojom::DeviceActivityStatus::New(
  184. test_devices()[3].instance_id(),
  185. /*last_activity_time=*/base::Time::FromTimeT(50),
  186. cryptauthv2::ConnectivityStatus::ONLINE,
  187. /*last_update_time=*/base::Time::FromTimeT(4)));
  188. device_activity_statuses.emplace_back(
  189. device_sync::mojom::DeviceActivityStatus::New(
  190. test_devices()[4].instance_id(),
  191. /*last_activity_time=*/base::Time::FromTimeT(50),
  192. cryptauthv2::ConnectivityStatus::ONLINE,
  193. /*last_update_time=*/base::Time::FromTimeT(3)));
  194. if (use_get_devices_activity_status()) {
  195. fake_device_sync_client()->InvokePendingGetDevicesActivityStatusCallback(
  196. device_sync::mojom::NetworkRequestResult::kSuccess,
  197. std::move(device_activity_statuses));
  198. }
  199. multidevice::RemoteDeviceRefList eligible_devices =
  200. provider()->GetEligibleHostDevices();
  201. multidevice::DeviceWithConnectivityStatusList eligible_active_devices =
  202. provider()->GetEligibleActiveHostDevices();
  203. if (use_get_devices_activity_status()) {
  204. // Verify sorting by online/offline status (if flag enabled), then by
  205. // |last_activity_time|, then by |last_update_time| (from
  206. // GetDevicesActivityStatus), then by |last_update_time_millis| (from
  207. // RemoteDevice).
  208. if (use_connectivity_status()) {
  209. if (use_last_activity_time_to_dedup()) {
  210. // If the kCryptAuthV2DedupDeviceLastActivityTime flag is enabled, only
  211. // the first one of devices sharing same last_activity_time will be
  212. // kept, sorted by online/offline status, last_update_time, and
  213. // last_update_time_millis.
  214. EXPECT_EQ(3u, eligible_active_devices.size());
  215. EXPECT_EQ(test_devices()[2], eligible_active_devices[0].remote_device);
  216. EXPECT_EQ(test_devices()[3], eligible_active_devices[1].remote_device);
  217. EXPECT_EQ(test_devices()[1], eligible_active_devices[2].remote_device);
  218. } else {
  219. EXPECT_EQ(5u, eligible_active_devices.size());
  220. EXPECT_EQ(test_devices()[2], eligible_active_devices[0].remote_device);
  221. EXPECT_EQ(test_devices()[3], eligible_active_devices[1].remote_device);
  222. EXPECT_EQ(test_devices()[0], eligible_active_devices[2].remote_device);
  223. EXPECT_EQ(test_devices()[4], eligible_active_devices[3].remote_device);
  224. EXPECT_EQ(test_devices()[1], eligible_active_devices[4].remote_device);
  225. // Verify connectivity statuses.
  226. EXPECT_EQ(cryptauthv2::ConnectivityStatus::ONLINE,
  227. eligible_active_devices[0].connectivity_status);
  228. EXPECT_EQ(cryptauthv2::ConnectivityStatus::ONLINE,
  229. eligible_active_devices[1].connectivity_status);
  230. EXPECT_EQ(cryptauthv2::ConnectivityStatus::ONLINE,
  231. eligible_active_devices[2].connectivity_status);
  232. EXPECT_EQ(cryptauthv2::ConnectivityStatus::ONLINE,
  233. eligible_active_devices[3].connectivity_status);
  234. EXPECT_EQ(cryptauthv2::ConnectivityStatus::OFFLINE,
  235. eligible_active_devices[4].connectivity_status);
  236. }
  237. } else {
  238. if (use_last_activity_time_to_dedup()) {
  239. // If the kCryptAuthV2DedupDeviceLastActivityTime flag is enabled, only
  240. // the first one of devices sharing same last_activity_time will be
  241. // kept, sorted by last_update_time and last_update_time_millis.
  242. EXPECT_EQ(3u, eligible_active_devices.size());
  243. EXPECT_EQ(test_devices()[2], eligible_active_devices[0].remote_device);
  244. EXPECT_EQ(test_devices()[1], eligible_active_devices[1].remote_device);
  245. EXPECT_EQ(test_devices()[3], eligible_active_devices[2].remote_device);
  246. } else {
  247. EXPECT_EQ(5u, eligible_active_devices.size());
  248. // Ignore online/offline statuses during sorting.
  249. EXPECT_EQ(test_devices()[2], eligible_active_devices[0].remote_device);
  250. EXPECT_EQ(test_devices()[1], eligible_active_devices[1].remote_device);
  251. EXPECT_EQ(test_devices()[3], eligible_active_devices[2].remote_device);
  252. EXPECT_EQ(test_devices()[0], eligible_active_devices[3].remote_device);
  253. EXPECT_EQ(test_devices()[4], eligible_active_devices[4].remote_device);
  254. }
  255. }
  256. } else {
  257. // Sorting solely based on RemoteDevice's |last_update_time_millis|.
  258. EXPECT_EQ(5u, eligible_devices.size());
  259. EXPECT_EQ(test_devices()[4], eligible_devices[0]);
  260. EXPECT_EQ(test_devices()[3], eligible_devices[1]);
  261. EXPECT_EQ(test_devices()[1], eligible_devices[2]);
  262. EXPECT_EQ(test_devices()[2], eligible_devices[3]);
  263. EXPECT_EQ(test_devices()[0], eligible_devices[4]);
  264. for (size_t i = 0; i < eligible_active_devices.size(); i++) {
  265. EXPECT_EQ(eligible_devices[i], eligible_active_devices[i].remote_device);
  266. }
  267. }
  268. if (always_use_active_eligible_devices()) {
  269. for (size_t i = 0; i < eligible_active_devices.size(); i++) {
  270. EXPECT_EQ(eligible_devices[i], eligible_active_devices[i].remote_device);
  271. }
  272. } else {
  273. EXPECT_EQ(5u, eligible_devices.size());
  274. }
  275. // Verify connectivity statuses.
  276. if (!use_get_devices_activity_status() || !use_connectivity_status()) {
  277. for (const auto& eligible_active_device : eligible_active_devices) {
  278. EXPECT_EQ(cryptauthv2::ConnectivityStatus::UNKNOWN_CONNECTIVITY,
  279. eligible_active_device.connectivity_status);
  280. }
  281. }
  282. }
  283. TEST_P(MultiDeviceSetupEligibleHostDevicesProviderImplTest,
  284. RemoveStaleDevices) {
  285. if (!use_get_devices_activity_status()) {
  286. return;
  287. }
  288. SetBitsOnTestDevices();
  289. base::subtle::ScopedTimeClockOverrides time_now_override(
  290. []() {
  291. return base::Time() +
  292. EligibleHostDevicesProviderImpl::kInactiveDeviceThresholdInDays +
  293. base::Days(1000);
  294. },
  295. nullptr, nullptr);
  296. multidevice::RemoteDeviceRefList devices{
  297. test_devices()[0], test_devices()[1], test_devices()[2],
  298. test_devices()[3], test_devices()[4], test_devices()[5]};
  299. fake_device_sync_client()->set_synced_devices(devices);
  300. fake_device_sync_client()->NotifyNewDevicesSynced();
  301. std::vector<device_sync::mojom::DeviceActivityStatusPtr>
  302. device_activity_statuses;
  303. // Do not filter out based on unset timestamps or based on connectivity
  304. // status.
  305. device_activity_statuses.emplace_back(
  306. device_sync::mojom::DeviceActivityStatus::New(
  307. test_devices()[0].instance_id(), /*last_activity_time=*/base::Time(),
  308. cryptauthv2::ConnectivityStatus::OFFLINE,
  309. /*last_update_time=*/base::Time()));
  310. // Filter out based on DeviceActivityStatus's |last_activity_time|.
  311. device_activity_statuses.emplace_back(
  312. device_sync::mojom::DeviceActivityStatus::New(
  313. test_devices()[1].instance_id(),
  314. /*last_activity_time=*/base::Time::Now() -
  315. EligibleHostDevicesProviderImpl::kInactiveDeviceThresholdInDays -
  316. base::Days(1),
  317. cryptauthv2::ConnectivityStatus::ONLINE,
  318. /*last_update_time=*/base::Time::Now()));
  319. // Filter out based on DeviceActivityStatus's |last_update_time|.
  320. device_activity_statuses.emplace_back(
  321. device_sync::mojom::DeviceActivityStatus::New(
  322. test_devices()[2].instance_id(),
  323. /*last_activity_time=*/base::Time::Now(),
  324. cryptauthv2::ConnectivityStatus::ONLINE,
  325. /*last_update_time=*/base::Time::Now() -
  326. EligibleHostDevicesProviderImpl::kInactiveDeviceThresholdInDays -
  327. base::Days(1)));
  328. // Do not filter out; times within threhhold
  329. device_activity_statuses.emplace_back(
  330. device_sync::mojom::DeviceActivityStatus::New(
  331. test_devices()[3].instance_id(),
  332. /*last_activity_time=*/base::Time::Now() -
  333. EligibleHostDevicesProviderImpl::kInactiveDeviceThresholdInDays,
  334. cryptauthv2::ConnectivityStatus::ONLINE,
  335. /*last_update_time=*/base::Time::Now() -
  336. EligibleHostDevicesProviderImpl::kInactiveDeviceThresholdInDays));
  337. // Do not filter out test_devices()[4]; no device activity status returned.
  338. fake_device_sync_client()->InvokePendingGetDevicesActivityStatusCallback(
  339. device_sync::mojom::NetworkRequestResult::kSuccess,
  340. std::move(device_activity_statuses));
  341. multidevice::DeviceWithConnectivityStatusList eligible_active_devices =
  342. provider()->GetEligibleActiveHostDevices();
  343. EXPECT_EQ(3u, eligible_active_devices.size());
  344. EXPECT_EQ(test_devices()[3], eligible_active_devices[0].remote_device);
  345. EXPECT_EQ(test_devices()[0], eligible_active_devices[1].remote_device);
  346. EXPECT_EQ(test_devices()[4], eligible_active_devices[2].remote_device);
  347. if (always_use_active_eligible_devices()) {
  348. multidevice::RemoteDeviceRefList eligible_devices =
  349. provider()->GetEligibleHostDevices();
  350. for (size_t i = 0; i < eligible_active_devices.size(); i++) {
  351. EXPECT_EQ(eligible_devices[i], eligible_active_devices[i].remote_device);
  352. }
  353. }
  354. }
  355. TEST_P(MultiDeviceSetupEligibleHostDevicesProviderImplTest,
  356. GetDevicesActivityStatusFailedRequest) {
  357. if (!use_get_devices_activity_status()) {
  358. return;
  359. }
  360. SetBitsOnTestDevices();
  361. GetMutableRemoteDevice(test_devices()[0])->last_update_time_millis = 5;
  362. GetMutableRemoteDevice(test_devices()[1])->last_update_time_millis = 4;
  363. GetMutableRemoteDevice(test_devices()[2])->last_update_time_millis = 3;
  364. GetMutableRemoteDevice(test_devices()[3])->last_update_time_millis = 2;
  365. GetMutableRemoteDevice(test_devices()[4])->last_update_time_millis = 1;
  366. multidevice::RemoteDeviceRefList devices{test_devices()[0], test_devices()[1],
  367. test_devices()[2], test_devices()[3],
  368. test_devices()[4]};
  369. fake_device_sync_client()->set_synced_devices(devices);
  370. fake_device_sync_client()->NotifyNewDevicesSynced();
  371. fake_device_sync_client()->InvokePendingGetDevicesActivityStatusCallback(
  372. device_sync::mojom::NetworkRequestResult::kInternalServerError,
  373. absl::nullopt);
  374. multidevice::DeviceWithConnectivityStatusList eligible_active_devices =
  375. provider()->GetEligibleActiveHostDevices();
  376. multidevice::RemoteDeviceRefList eligible_devices =
  377. provider()->GetEligibleHostDevices();
  378. EXPECT_EQ(test_devices()[0], eligible_active_devices[0].remote_device);
  379. EXPECT_EQ(test_devices()[1], eligible_active_devices[1].remote_device);
  380. EXPECT_EQ(test_devices()[2], eligible_active_devices[2].remote_device);
  381. EXPECT_EQ(test_devices()[3], eligible_active_devices[3].remote_device);
  382. EXPECT_EQ(test_devices()[0], eligible_devices[0]);
  383. EXPECT_EQ(test_devices()[1], eligible_devices[1]);
  384. EXPECT_EQ(test_devices()[2], eligible_devices[2]);
  385. EXPECT_EQ(test_devices()[3], eligible_devices[3]);
  386. }
  387. INSTANTIATE_TEST_SUITE_P(All,
  388. MultiDeviceSetupEligibleHostDevicesProviderImplTest,
  389. ::testing::Combine(::testing::Bool(),
  390. ::testing::Bool(),
  391. ::testing::Bool(),
  392. ::testing::Bool()));
  393. } // namespace multidevice_setup
  394. } // namespace ash