blob: e8748da0d77e20a04ef2e3780420d9dc5bce451e [file] [log] [blame]
Kyle Horimotoa75542612018-04-18 00:33:391// Copyright 2017 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#include "components/cryptauth/software_feature_manager_impl.h"
6
7#include "base/bind.h"
8#include "base/macros.h"
9#include "components/cryptauth/mock_cryptauth_client.h"
10#include "components/cryptauth/remote_device.h"
11#include "components/cryptauth/remote_device_test_util.h"
12#include "testing/gmock/include/gmock/gmock.h"
13#include "testing/gtest/include/gtest/gtest.h"
14
15using testing::_;
16using testing::Invoke;
17
18namespace cryptauth {
19
20namespace {
21
22const char kSuccessResult[] = "success";
23const char kErrorSetSoftwareFeatureState[] = "setSoftwareFeatureStateError";
24const char kErrorFindEligibleDevices[] = "findEligibleDevicesError";
25
26std::vector<cryptauth::ExternalDeviceInfo>
27CreateExternalDeviceInfosForRemoteDevices(
28 const std::vector<cryptauth::RemoteDevice> remote_devices) {
29 std::vector<cryptauth::ExternalDeviceInfo> device_infos;
30 for (const auto& remote_device : remote_devices) {
31 // Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
32 cryptauth::ExternalDeviceInfo info;
33 info.set_public_key(remote_device.public_key);
34 device_infos.push_back(info);
35 }
36 return device_infos;
37}
38
39} // namespace
40
41class CryptAuthSoftwareFeatureManagerImplTest
42 : public testing::Test,
43 public MockCryptAuthClientFactory::Observer {
44 public:
45 CryptAuthSoftwareFeatureManagerImplTest()
46 : all_test_external_device_infos_(
47 CreateExternalDeviceInfosForRemoteDevices(
48 cryptauth::GenerateTestRemoteDevices(5))),
49 test_eligible_external_devices_infos_(
50 {all_test_external_device_infos_[0],
51 all_test_external_device_infos_[1],
52 all_test_external_device_infos_[2]}),
53 test_ineligible_external_devices_infos_(
54 {all_test_external_device_infos_[3],
55 all_test_external_device_infos_[4]}) {}
56
57 void SetUp() override {
58 mock_cryptauth_client_factory_ =
59 std::make_unique<MockCryptAuthClientFactory>(
60 MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS);
61 mock_cryptauth_client_factory_->AddObserver(this);
62 software_feature_manager_ =
63 SoftwareFeatureManagerImpl::Factory::NewInstance(
64 mock_cryptauth_client_factory_.get());
65 }
66
67 void TearDown() override {
68 mock_cryptauth_client_factory_->RemoveObserver(this);
69 }
70
71 void OnCryptAuthClientCreated(MockCryptAuthClient* client) override {
72 ON_CALL(*client, ToggleEasyUnlock(_, _, _))
73 .WillByDefault(Invoke(
74 this,
75 &CryptAuthSoftwareFeatureManagerImplTest::MockToggleEasyUnlock));
76 ON_CALL(*client, FindEligibleUnlockDevices(_, _, _))
77 .WillByDefault(Invoke(this, &CryptAuthSoftwareFeatureManagerImplTest::
78 MockFindEligibleUnlockDevices));
79 }
80
81 // Mock CryptAuthClient::ToggleEasyUnlock() implementation.
82 void MockToggleEasyUnlock(
83 const ToggleEasyUnlockRequest& request,
84 const CryptAuthClient::ToggleEasyUnlockCallback& callback,
85 const CryptAuthClient::ErrorCallback& error_callback) {
86 last_toggle_request_ = request;
87 toggle_easy_unlock_callback_ = callback;
88 error_callback_ = error_callback;
89 error_code_ = kErrorSetSoftwareFeatureState;
90 }
91
92 // Mock CryptAuthClient::FindEligibleUnlockDevices() implementation.
93 void MockFindEligibleUnlockDevices(
94 const FindEligibleUnlockDevicesRequest& request,
95 const CryptAuthClient::FindEligibleUnlockDevicesCallback& callback,
96 const CryptAuthClient::ErrorCallback& error_callback) {
97 last_find_request_ = request;
98 find_eligible_unlock_devices_callback_ = callback;
99 error_callback_ = error_callback;
100 error_code_ = kErrorFindEligibleDevices;
101 }
102
103 FindEligibleUnlockDevicesResponse CreateFindEligibleUnlockDevicesResponse() {
104 FindEligibleUnlockDevicesResponse find_eligible_unlock_devices_response;
105 for (const auto& device_info : test_eligible_external_devices_infos_) {
106 find_eligible_unlock_devices_response.add_eligible_devices()->CopyFrom(
107 device_info);
108 }
109 for (const auto& device_info : test_ineligible_external_devices_infos_) {
110 find_eligible_unlock_devices_response.add_ineligible_devices()
111 ->mutable_device()
112 ->CopyFrom(device_info);
113 }
114 return find_eligible_unlock_devices_response;
115 }
116
117 void VerifyDeviceEligibility() {
118 // Ensure that resulting devices are not empty. Otherwise, following for
119 // loop checks will succeed on empty resulting devices.
120 EXPECT_TRUE(result_eligible_devices_.size() > 0);
121 EXPECT_TRUE(result_ineligible_devices_.size() > 0);
122 for (const auto& device_info : result_eligible_devices_) {
123 EXPECT_TRUE(
124 std::find_if(
125 test_eligible_external_devices_infos_.begin(),
126 test_eligible_external_devices_infos_.end(),
127 [&device_info](const cryptauth::ExternalDeviceInfo& device) {
128 return device.public_key() == device_info.public_key();
129 }) != test_eligible_external_devices_infos_.end());
130 }
131 for (const auto& ineligible_device : result_ineligible_devices_) {
132 EXPECT_TRUE(
133 std::find_if(test_ineligible_external_devices_infos_.begin(),
134 test_ineligible_external_devices_infos_.end(),
135 [&ineligible_device](
136 const cryptauth::ExternalDeviceInfo& device) {
137 return device.public_key() ==
138 ineligible_device.device().public_key();
139 }) != test_ineligible_external_devices_infos_.end());
140 }
141 result_eligible_devices_.clear();
142 result_ineligible_devices_.clear();
143 }
144
145 void SetSoftwareFeatureState(SoftwareFeature feature,
146 const ExternalDeviceInfo& device_info,
147 bool enabled,
148 bool is_exclusive = false) {
149 software_feature_manager_->SetSoftwareFeatureState(
150 device_info.public_key(), feature, enabled,
151 base::Bind(
152 &CryptAuthSoftwareFeatureManagerImplTest::OnSoftwareFeatureStateSet,
153 base::Unretained(this)),
154 base::Bind(&CryptAuthSoftwareFeatureManagerImplTest::OnError,
155 base::Unretained(this)),
156 is_exclusive);
157 }
158
159 void FindEligibleDevices(SoftwareFeature feature) {
160 software_feature_manager_->FindEligibleDevices(
161 feature,
162 base::Bind(
163 &CryptAuthSoftwareFeatureManagerImplTest::OnEligibleDevicesFound,
164 base::Unretained(this)),
165 base::Bind(&CryptAuthSoftwareFeatureManagerImplTest::OnError,
166 base::Unretained(this)));
167 }
168
169 void OnSoftwareFeatureStateSet() { result_ = kSuccessResult; }
170
171 void OnEligibleDevicesFound(
172 const std::vector<ExternalDeviceInfo>& eligible_devices,
173 const std::vector<IneligibleDevice>& ineligible_devices) {
174 result_ = kSuccessResult;
175 result_eligible_devices_ = eligible_devices;
176 result_ineligible_devices_ = ineligible_devices;
177 }
178
179 void OnError(const std::string& error_message) { result_ = error_message; }
180
181 void InvokeSetSoftwareFeatureCallback() {
182 CryptAuthClient::ToggleEasyUnlockCallback success_callback =
183 toggle_easy_unlock_callback_;
184 ASSERT_TRUE(!success_callback.is_null());
185 toggle_easy_unlock_callback_.Reset();
186 success_callback.Run(ToggleEasyUnlockResponse());
187 }
188
189 void InvokeFindEligibleDevicesCallback(
190 const FindEligibleUnlockDevicesResponse& retrieved_devices_response) {
191 CryptAuthClient::FindEligibleUnlockDevicesCallback success_callback =
192 find_eligible_unlock_devices_callback_;
193 ASSERT_TRUE(!success_callback.is_null());
194 find_eligible_unlock_devices_callback_.Reset();
195 success_callback.Run(retrieved_devices_response);
196 }
197
198 void InvokeErrorCallback() {
199 CryptAuthClient::ErrorCallback error_callback = error_callback_;
200 ASSERT_TRUE(!error_callback.is_null());
201 error_callback_.Reset();
202 error_callback.Run(error_code_);
203 }
204
205 std::string GetResultAndReset() {
206 std::string result;
207 result.swap(result_);
208 return result;
209 }
210
211 const std::vector<cryptauth::ExternalDeviceInfo>
212 all_test_external_device_infos_;
213 const std::vector<ExternalDeviceInfo> test_eligible_external_devices_infos_;
214 const std::vector<ExternalDeviceInfo> test_ineligible_external_devices_infos_;
215
216 std::unique_ptr<MockCryptAuthClientFactory> mock_cryptauth_client_factory_;
217 std::unique_ptr<cryptauth::SoftwareFeatureManager> software_feature_manager_;
218
219 CryptAuthClient::ErrorCallback error_callback_;
220
221 // Set when a CryptAuthClient function returns. If empty, no callback has been
222 // invoked.
223 std::string result_;
224
225 // The code passed to the error callback; varies depending on what
226 // CryptAuthClient function is invoked.
227 std::string error_code_;
228
229 // For SetSoftwareFeatureState() tests.
230 ToggleEasyUnlockRequest last_toggle_request_;
231 CryptAuthClient::ToggleEasyUnlockCallback toggle_easy_unlock_callback_;
232
233 // For FindEligibleDevices() tests.
234 FindEligibleUnlockDevicesRequest last_find_request_;
235 CryptAuthClient::FindEligibleUnlockDevicesCallback
236 find_eligible_unlock_devices_callback_;
237 std::vector<ExternalDeviceInfo> result_eligible_devices_;
238 std::vector<IneligibleDevice> result_ineligible_devices_;
239
240 private:
241 DISALLOW_COPY_AND_ASSIGN(CryptAuthSoftwareFeatureManagerImplTest);
242};
243
244TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestOrderUponMultipleRequests) {
245 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
246 test_eligible_external_devices_infos_[0],
247 true /* enable */);
248 FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
249 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_CLIENT,
250 test_eligible_external_devices_infos_[1],
251 false /* enable */);
252 FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_CLIENT);
253
254 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
255 last_toggle_request_.feature());
256 EXPECT_EQ(true, last_toggle_request_.enable());
257 EXPECT_EQ(false, last_toggle_request_.is_exclusive());
258 InvokeSetSoftwareFeatureCallback();
259 EXPECT_EQ(kSuccessResult, GetResultAndReset());
260
261 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
262 last_find_request_.feature());
263 InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
264 EXPECT_EQ(kSuccessResult, GetResultAndReset());
265 VerifyDeviceEligibility();
266
267 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
268 last_toggle_request_.feature());
269 EXPECT_EQ(false, last_toggle_request_.enable());
270 EXPECT_EQ(false, last_toggle_request_.is_exclusive());
271 InvokeSetSoftwareFeatureCallback();
272 EXPECT_EQ(kSuccessResult, GetResultAndReset());
273
274 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
275 last_find_request_.feature());
276 InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
277 EXPECT_EQ(kSuccessResult, GetResultAndReset());
278 VerifyDeviceEligibility();
279}
280
281TEST_F(CryptAuthSoftwareFeatureManagerImplTest,
282 TestMultipleSetUnlocksRequests) {
283 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
284 test_eligible_external_devices_infos_[0],
285 true /* enable */);
286 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_CLIENT,
287 test_eligible_external_devices_infos_[1],
288 false /* enable */);
289 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
290 test_eligible_external_devices_infos_[2],
291 true /* enable */);
292
293 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
294 last_toggle_request_.feature());
295 EXPECT_EQ(true, last_toggle_request_.enable());
296 EXPECT_EQ(false, last_toggle_request_.is_exclusive());
297 InvokeErrorCallback();
298 EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
299
300 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
301 last_toggle_request_.feature());
302 EXPECT_EQ(false, last_toggle_request_.enable());
303 EXPECT_EQ(false, last_toggle_request_.is_exclusive());
304 InvokeSetSoftwareFeatureCallback();
305 EXPECT_EQ(kSuccessResult, GetResultAndReset());
306
307 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
308 last_toggle_request_.feature());
309 EXPECT_EQ(true, last_toggle_request_.enable());
310 EXPECT_EQ(false, last_toggle_request_.is_exclusive());
311 InvokeSetSoftwareFeatureCallback();
312 EXPECT_EQ(kSuccessResult, GetResultAndReset());
313}
314
315TEST_F(CryptAuthSoftwareFeatureManagerImplTest,
316 TestMultipleFindEligibleForUnlockDevicesRequests) {
317 FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
318 FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_CLIENT);
319 FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
320
321 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
322 last_find_request_.feature());
323 InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
324 EXPECT_EQ(kSuccessResult, GetResultAndReset());
325 VerifyDeviceEligibility();
326
327 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
328 last_find_request_.feature());
329 InvokeErrorCallback();
330 EXPECT_EQ(kErrorFindEligibleDevices, GetResultAndReset());
331
332 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
333 last_find_request_.feature());
334 InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
335 EXPECT_EQ(kSuccessResult, GetResultAndReset());
336 VerifyDeviceEligibility();
337}
338
339TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestOrderViaMultipleErrors) {
340 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
341 test_eligible_external_devices_infos_[0],
342 true /* enable */);
343 FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
344
345 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
346 last_toggle_request_.feature());
347 InvokeErrorCallback();
348 EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
349
350 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
351 last_find_request_.feature());
352 InvokeErrorCallback();
353 EXPECT_EQ(kErrorFindEligibleDevices, GetResultAndReset());
354}
355
356TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestIsExclusive) {
357 SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
358 test_eligible_external_devices_infos_[0],
359 true /* enable */, true /* is_exclusive */);
360
361 EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
362 last_toggle_request_.feature());
363 EXPECT_EQ(true, last_toggle_request_.enable());
364 EXPECT_EQ(true, last_toggle_request_.is_exclusive());
365 InvokeErrorCallback();
366 EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
367}
368
369TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestEasyUnlockSpecialCase) {
370 SetSoftwareFeatureState(SoftwareFeature::EASY_UNLOCK_HOST,
371 test_eligible_external_devices_infos_[0],
372 false /* enable */);
373
374 EXPECT_EQ(SoftwareFeature::EASY_UNLOCK_HOST, last_toggle_request_.feature());
375 EXPECT_EQ(false, last_toggle_request_.enable());
376 // apply_to_all() should be false when disabling EasyUnlock host capabilities.
377 EXPECT_EQ(true, last_toggle_request_.apply_to_all());
378 InvokeErrorCallback();
379 EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
380}
381
382} // namespace cryptauth