blob: a3bbf97cffc2206135a56c9b87c17affbd08ab3b [file] [log] [blame]
Regan Hsu1f1aa4c2017-08-02 02:05:231// Copyright 2016 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
Regan Hsu9fc97cc2017-09-08 03:13:515#include "components/cryptauth/remote_device_provider_impl.h"
Regan Hsu1f1aa4c2017-08-02 02:05:236
7#include <memory>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/memory/ptr_util.h"
12#include "base/run_loop.h"
13#include "components/cryptauth/cryptauth_device_manager.h"
Kyle Horimoto3cb4b2b2018-02-14 18:07:1814#include "components/cryptauth/fake_cryptauth_device_manager.h"
Regan Hsu1f1aa4c2017-08-02 02:05:2315#include "components/cryptauth/fake_secure_message_delegate.h"
16#include "components/cryptauth/proto/cryptauth_api.pb.h"
17#include "components/cryptauth/remote_device_loader.h"
18#include "components/cryptauth/remote_device_test_util.h"
Kyle Horimoto691afaa12018-04-04 01:56:1619#include "components/cryptauth/secure_message_delegate_impl.h"
Regan Hsu1f1aa4c2017-08-02 02:05:2320#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gtest/include/gtest/gtest.h"
22
23using testing::_;
24using testing::Invoke;
25using testing::NiceMock;
26using testing::Return;
27
28namespace cryptauth {
29
30namespace {
31
32const char kTestUserId[] = "testUserId";
33const char kTestUserPrivateKey[] = "kTestUserPrivateKey";
34
Regan Hsu1f1aa4c2017-08-02 02:05:2335class FakeSecureMessageDelegateFactory
Kyle Horimoto691afaa12018-04-04 01:56:1636 : public cryptauth::SecureMessageDelegateImpl::Factory {
Regan Hsu1f1aa4c2017-08-02 02:05:2337 public:
Kyle Horimoto691afaa12018-04-04 01:56:1638 // cryptauth::SecureMessageDelegateImpl::Factory:
39 std::unique_ptr<cryptauth::SecureMessageDelegate> BuildInstance() override {
Regan Hsu1f1aa4c2017-08-02 02:05:2340 cryptauth::FakeSecureMessageDelegate* delegate =
41 new cryptauth::FakeSecureMessageDelegate();
42 created_delegates_.push_back(delegate);
43 return base::WrapUnique(delegate);
44 }
45
46 private:
47 std::vector<cryptauth::FakeSecureMessageDelegate*> created_delegates_;
48};
49
50std::vector<cryptauth::ExternalDeviceInfo>
51CreateExternalDeviceInfosForRemoteDevices(
52 const std::vector<cryptauth::RemoteDevice> remote_devices) {
53 std::vector<cryptauth::ExternalDeviceInfo> device_infos;
54 for (const auto& remote_device : remote_devices) {
55 // Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
56 cryptauth::ExternalDeviceInfo info;
57 info.set_public_key(remote_device.public_key);
58 device_infos.push_back(info);
59 }
60 return device_infos;
61}
62
63class TestObserver : public RemoteDeviceProvider::Observer {
64 public:
65 TestObserver() {}
66 ~TestObserver() override {}
67
68 int num_times_device_list_changed() { return num_times_device_list_changed_; }
69
70 // RemoteDeviceProvider::Observer:
71 void OnSyncDeviceListChanged() override { num_times_device_list_changed_++; }
72
73 private:
74 int num_times_device_list_changed_ = 0;
75};
76
77} // namespace
78
Nico Weber564d3502017-08-30 20:14:1579class FakeDeviceLoader final : public cryptauth::RemoteDeviceLoader {
Regan Hsu1f1aa4c2017-08-02 02:05:2380 public:
Nico Weber564d3502017-08-30 20:14:1581 class TestRemoteDeviceLoaderFactory final
82 : public RemoteDeviceLoader::Factory {
Regan Hsu1f1aa4c2017-08-02 02:05:2383 public:
84 explicit TestRemoteDeviceLoaderFactory()
85 : test_devices_(cryptauth::GenerateTestRemoteDevices(5)),
86 test_device_infos_(
87 CreateExternalDeviceInfosForRemoteDevices(test_devices_)) {}
88
89 ~TestRemoteDeviceLoaderFactory() {}
90
91 std::unique_ptr<RemoteDeviceLoader> BuildInstance(
92 const std::vector<cryptauth::ExternalDeviceInfo>& device_info_list,
93 const std::string& user_id,
94 const std::string& user_private_key,
95 std::unique_ptr<cryptauth::SecureMessageDelegate>
96 secure_message_delegate) override {
97 EXPECT_EQ(std::string(kTestUserId), user_id);
98 EXPECT_EQ(std::string(kTestUserPrivateKey), user_private_key);
99 std::unique_ptr<FakeDeviceLoader> device_loader =
Gyuyoung Kim6afb5082018-01-19 13:35:57100 std::make_unique<FakeDeviceLoader>();
Regan Hsu1f1aa4c2017-08-02 02:05:23101 device_loader->remote_device_loader_factory_ = this;
102 return std::move(device_loader);
103 }
104
105 void InvokeLastCallback(
106 const std::vector<cryptauth::ExternalDeviceInfo>& device_info_list) {
107 ASSERT_TRUE(!callback_.is_null());
108 // Fetch only the devices inserted by tests, since test_devices_ contains
109 // all available devices.
110 std::vector<RemoteDevice> devices;
111 for (const auto& remote_device : test_devices_) {
112 for (const auto& external_device_info : device_info_list) {
113 if (remote_device.public_key == external_device_info.public_key())
114 devices.push_back(remote_device);
115 }
116 }
117 callback_.Run(devices);
118 callback_.Reset();
119 }
120
121 // Fetch is only started if the change result passed to OnSyncFinished() is
122 // CHANGED and sync is SUCCESS.
123 bool HasQueuedCallback() { return !callback_.is_null(); }
124 const std::vector<cryptauth::RemoteDevice> test_devices_;
125 const std::vector<cryptauth::ExternalDeviceInfo> test_device_infos_;
126
127 void QueueCallback(const RemoteDeviceCallback& callback) {
128 callback_ = callback;
129 }
130
131 private:
132 cryptauth::RemoteDeviceLoader::RemoteDeviceCallback callback_;
133 };
134
135 FakeDeviceLoader()
136 : cryptauth::RemoteDeviceLoader(
137 std::vector<cryptauth::ExternalDeviceInfo>(),
138 "",
139 "",
140 nullptr) {}
141
142 ~FakeDeviceLoader() override {}
143
144 TestRemoteDeviceLoaderFactory* remote_device_loader_factory_;
145
146 void Load(bool should_load_beacon_seeds,
147 const RemoteDeviceCallback& callback) override {
148 remote_device_loader_factory_->QueueCallback(callback);
149 }
150};
151
Regan Hsu9fc97cc2017-09-08 03:13:51152class RemoteDeviceProviderImplTest : public testing::Test {
Regan Hsu1f1aa4c2017-08-02 02:05:23153 public:
Regan Hsu9fc97cc2017-09-08 03:13:51154 RemoteDeviceProviderImplTest() {}
Regan Hsu1f1aa4c2017-08-02 02:05:23155
156 void SetUp() override {
Kyle Horimoto3cb4b2b2018-02-14 18:07:18157 fake_device_manager_ = std::make_unique<FakeCryptAuthDeviceManager>();
Regan Hsu1f1aa4c2017-08-02 02:05:23158 fake_secure_message_delegate_factory_ =
Gyuyoung Kim6afb5082018-01-19 13:35:57159 std::make_unique<FakeSecureMessageDelegateFactory>();
Kyle Horimoto691afaa12018-04-04 01:56:16160 cryptauth::SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
161 fake_secure_message_delegate_factory_.get());
Regan Hsu1f1aa4c2017-08-02 02:05:23162 test_device_loader_factory_ =
Gyuyoung Kim6afb5082018-01-19 13:35:57163 std::make_unique<FakeDeviceLoader::TestRemoteDeviceLoaderFactory>();
Regan Hsu1f1aa4c2017-08-02 02:05:23164 cryptauth::RemoteDeviceLoader::Factory::SetInstanceForTesting(
165 test_device_loader_factory_.get());
Gyuyoung Kim6afb5082018-01-19 13:35:57166 test_observer_ = std::make_unique<TestObserver>();
Regan Hsu1f1aa4c2017-08-02 02:05:23167 }
168
Kyle Horimoto691afaa12018-04-04 01:56:16169 void TearDown() override {
170 cryptauth::SecureMessageDelegateImpl::Factory::SetInstanceForTesting(
171 nullptr);
172 }
173
Regan Hsu1f1aa4c2017-08-02 02:05:23174 void CreateRemoteDeviceProvider() {
Gyuyoung Kim6afb5082018-01-19 13:35:57175 remote_device_provider_ = std::make_unique<RemoteDeviceProviderImpl>(
Kyle Horimoto691afaa12018-04-04 01:56:16176 fake_device_manager_.get(), kTestUserId, kTestUserPrivateKey);
Regan Hsu1f1aa4c2017-08-02 02:05:23177 remote_device_provider_->AddObserver(test_observer_.get());
178 EXPECT_EQ(0u, remote_device_provider_->GetSyncedDevices().size());
179 test_device_loader_factory_->InvokeLastCallback(
Kyle Horimoto3cb4b2b2018-02-14 18:07:18180 fake_device_manager_->GetSyncedDevices());
Regan Hsu1f1aa4c2017-08-02 02:05:23181 VerifySyncedDevicesMatchExpectation(
Kyle Horimoto3cb4b2b2018-02-14 18:07:18182 fake_device_manager_->GetSyncedDevices().size());
Regan Hsu1f1aa4c2017-08-02 02:05:23183 }
184
185 void VerifySyncedDevicesMatchExpectation(size_t expected_size) {
186 std::vector<cryptauth::RemoteDevice> synced_devices =
187 remote_device_provider_->GetSyncedDevices();
188 EXPECT_EQ(expected_size, synced_devices.size());
Kyle Horimoto3cb4b2b2018-02-14 18:07:18189 EXPECT_EQ(expected_size, fake_device_manager_->GetSyncedDevices().size());
Regan Hsu1f1aa4c2017-08-02 02:05:23190 std::unordered_set<std::string> public_keys;
Kyle Horimoto3cb4b2b2018-02-14 18:07:18191 for (const auto& device_info : fake_device_manager_->GetSyncedDevices()) {
Regan Hsu1f1aa4c2017-08-02 02:05:23192 public_keys.insert(device_info.public_key());
193 }
194 for (const auto& remote_device : synced_devices) {
195 EXPECT_TRUE(public_keys.find(remote_device.public_key) !=
196 public_keys.end());
197 }
198 }
199
Regan Hsu1f1aa4c2017-08-02 02:05:23200 std::vector<cryptauth::RemoteDevice> test_devices() {
201 return test_device_loader_factory_->test_devices_;
202 }
203
204 ExternalDeviceInfo test_device_infos_(int val) {
205 return test_device_loader_factory_->test_device_infos_[val];
206 }
207
Regan Hsu1f1aa4c2017-08-02 02:05:23208 std::unique_ptr<FakeSecureMessageDelegateFactory>
209 fake_secure_message_delegate_factory_;
210
Kyle Horimoto3cb4b2b2018-02-14 18:07:18211 std::unique_ptr<FakeCryptAuthDeviceManager> fake_device_manager_;
Regan Hsu1f1aa4c2017-08-02 02:05:23212
213 std::unique_ptr<FakeDeviceLoader::TestRemoteDeviceLoaderFactory>
214 test_device_loader_factory_;
215
Regan Hsu9fc97cc2017-09-08 03:13:51216 std::unique_ptr<RemoteDeviceProviderImpl> remote_device_provider_;
Regan Hsu1f1aa4c2017-08-02 02:05:23217
218 std::unique_ptr<TestObserver> test_observer_;
219
220 private:
Regan Hsu9fc97cc2017-09-08 03:13:51221 DISALLOW_COPY_AND_ASSIGN(RemoteDeviceProviderImplTest);
Regan Hsu1f1aa4c2017-08-02 02:05:23222};
223
Regan Hsu9fc97cc2017-09-08 03:13:51224TEST_F(RemoteDeviceProviderImplTest, TestMultipleSyncs) {
Regan Hsu1f1aa4c2017-08-02 02:05:23225 // Initialize with devices 0 and 1.
Kyle Horimoto3cb4b2b2018-02-14 18:07:18226 fake_device_manager_->synced_devices().push_back(test_device_infos_(0));
227 fake_device_manager_->synced_devices().push_back(test_device_infos_(1));
Regan Hsu1f1aa4c2017-08-02 02:05:23228 CreateRemoteDeviceProvider();
229 VerifySyncedDevicesMatchExpectation(2u /* expected_size */);
230 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
231
232 // Now add device 2 and trigger another sync.
Kyle Horimoto3cb4b2b2018-02-14 18:07:18233 fake_device_manager_->synced_devices().push_back(test_device_infos_(2));
234 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23235 CryptAuthDeviceManager::SyncResult::SUCCESS,
236 CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
237 test_device_loader_factory_->InvokeLastCallback(
Kyle Horimoto3cb4b2b2018-02-14 18:07:18238 fake_device_manager_->GetSyncedDevices());
Regan Hsu1f1aa4c2017-08-02 02:05:23239 VerifySyncedDevicesMatchExpectation(3u /* expected_size */);
240 EXPECT_EQ(2, test_observer_->num_times_device_list_changed());
241
242 // Now, simulate a sync which shows that device 0 was removed.
Kyle Horimoto3cb4b2b2018-02-14 18:07:18243 fake_device_manager_->synced_devices().erase(
244 fake_device_manager_->synced_devices().begin());
245 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23246 CryptAuthDeviceManager::SyncResult::SUCCESS,
247 CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
248 test_device_loader_factory_->InvokeLastCallback(
Kyle Horimoto3cb4b2b2018-02-14 18:07:18249 fake_device_manager_->GetSyncedDevices());
Regan Hsu1f1aa4c2017-08-02 02:05:23250 VerifySyncedDevicesMatchExpectation(2u /* expected_size */);
251 EXPECT_EQ(3, test_observer_->num_times_device_list_changed());
252}
253
Regan Hsu9fc97cc2017-09-08 03:13:51254TEST_F(RemoteDeviceProviderImplTest,
255 TestNotifySyncFinishedParameterCombinations) {
Kyle Horimoto3cb4b2b2018-02-14 18:07:18256 fake_device_manager_->synced_devices().push_back(test_device_infos_(0));
Regan Hsu1f1aa4c2017-08-02 02:05:23257 CreateRemoteDeviceProvider();
258 VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
Kyle Horimoto3cb4b2b2018-02-14 18:07:18259 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23260 CryptAuthDeviceManager::SyncResult::FAILURE,
261 CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
262 EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
263 VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
264 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
265
Kyle Horimoto3cb4b2b2018-02-14 18:07:18266 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23267 CryptAuthDeviceManager::SyncResult::SUCCESS,
268 CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
269 EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
270 VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
271 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
272
Kyle Horimoto3cb4b2b2018-02-14 18:07:18273 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23274 CryptAuthDeviceManager::SyncResult::FAILURE,
275 CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
276 EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
277 VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
278 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
279
Kyle Horimoto3cb4b2b2018-02-14 18:07:18280 fake_device_manager_->synced_devices().push_back(test_device_infos_(1));
281 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23282 CryptAuthDeviceManager::SyncResult::SUCCESS,
283 CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
284 test_device_loader_factory_->InvokeLastCallback(
Kyle Horimoto3cb4b2b2018-02-14 18:07:18285 fake_device_manager_->GetSyncedDevices());
Regan Hsu1f1aa4c2017-08-02 02:05:23286 VerifySyncedDevicesMatchExpectation(2u /* expected_size */);
287 EXPECT_EQ(2, test_observer_->num_times_device_list_changed());
288}
289
Regan Hsu9fc97cc2017-09-08 03:13:51290TEST_F(RemoteDeviceProviderImplTest, TestNewSyncDuringDeviceRegeneration) {
Kyle Horimoto3cb4b2b2018-02-14 18:07:18291 fake_device_manager_->synced_devices().push_back(test_device_infos_(0));
Regan Hsu1f1aa4c2017-08-02 02:05:23292 CreateRemoteDeviceProvider();
293 VerifySyncedDevicesMatchExpectation(1u /* expected_size */);
294
295 // Add device 1 and trigger a sync.
Kyle Horimoto3cb4b2b2018-02-14 18:07:18296 fake_device_manager_->synced_devices().push_back(test_device_infos_(1));
297 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23298 CryptAuthDeviceManager::SyncResult::SUCCESS,
299 CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
300 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
301
302 // Do not wait for the new devices to be generated (i.e., don't call
303 // test_device_loader_factory_->InvokeLastCallback() yet). Trigger a new
304 // sync with device 2 included.
Kyle Horimoto3cb4b2b2018-02-14 18:07:18305 fake_device_manager_->synced_devices().push_back(test_device_infos_(2));
306 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23307 CryptAuthDeviceManager::SyncResult::SUCCESS,
308 CryptAuthDeviceManager::DeviceChangeResult::CHANGED);
309 test_device_loader_factory_->InvokeLastCallback(
Kyle Horimoto3cb4b2b2018-02-14 18:07:18310 fake_device_manager_->GetSyncedDevices());
Regan Hsu1f1aa4c2017-08-02 02:05:23311 VerifySyncedDevicesMatchExpectation(3u /* expected_size */);
312 EXPECT_EQ(2, test_observer_->num_times_device_list_changed());
313}
314
Regan Hsu9fc97cc2017-09-08 03:13:51315TEST_F(RemoteDeviceProviderImplTest, TestZeroSyncedDevices) {
Regan Hsu1f1aa4c2017-08-02 02:05:23316 CreateRemoteDeviceProvider();
317 VerifySyncedDevicesMatchExpectation(0 /* expected_size */);
318 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
Kyle Horimoto3cb4b2b2018-02-14 18:07:18319 fake_device_manager_->NotifySyncFinished(
Regan Hsu1f1aa4c2017-08-02 02:05:23320 CryptAuthDeviceManager::SyncResult::SUCCESS,
321 CryptAuthDeviceManager::DeviceChangeResult::UNCHANGED);
322 EXPECT_FALSE(test_device_loader_factory_->HasQueuedCallback());
323 VerifySyncedDevicesMatchExpectation(0 /* expected_size */);
324 EXPECT_EQ(1, test_observer_->num_times_device_list_changed());
325}
326
327} // namespace cryptauth