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 
5 #include "ash/detachable_base/detachable_base_handler.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "ash/detachable_base/detachable_base_observer.h"
11 #include "ash/detachable_base/detachable_base_pairing_status.h"
12 #include "ash/public/cpp/session/user_info.h"
13 #include "base/macros.h"
14 #include "base/run_loop.h"
15 #include "base/test/task_environment.h"
16 #include "base/time/time.h"
17 #include "chromeos/dbus/hammerd/fake_hammerd_client.h"
18 #include "chromeos/dbus/power/fake_power_manager_client.h"
19 #include "components/account_id/account_id.h"
20 #include "components/prefs/testing_pref_service.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 namespace ash {
24 
25 namespace {
26 
27 enum class UserType {
28   kNormal,
29   kEphemeral,
30 };
31 
CreateUser(const std::string & email,const std::string & gaia_id,UserType user_type)32 UserInfo CreateUser(const std::string& email,
33                     const std::string& gaia_id,
34                     UserType user_type) {
35   UserInfo user;
36   user.account_id = AccountId::FromUserEmailGaiaId(email, gaia_id);
37   user.is_ephemeral = user_type == UserType::kEphemeral;
38   return user;
39 }
40 
41 class TestBaseObserver : public DetachableBaseObserver {
42  public:
43   TestBaseObserver() = default;
44   ~TestBaseObserver() override = default;
45 
pairing_status_changed_count() const46   int pairing_status_changed_count() const {
47     return pairing_status_changed_count_;
48   }
49 
reset_pairing_status_changed_count()50   void reset_pairing_status_changed_count() {
51     pairing_status_changed_count_ = 0;
52   }
53 
update_required_changed_count() const54   int update_required_changed_count() const {
55     return update_required_changed_count_;
56   }
57 
requires_update() const58   bool requires_update() const { return requires_update_; }
59 
60   // DetachableBaseObserver:
OnDetachableBasePairingStatusChanged(DetachableBasePairingStatus status)61   void OnDetachableBasePairingStatusChanged(
62       DetachableBasePairingStatus status) override {
63     pairing_status_changed_count_++;
64   }
65 
OnDetachableBaseRequiresUpdateChanged(bool requires_update)66   void OnDetachableBaseRequiresUpdateChanged(bool requires_update) override {
67     update_required_changed_count_++;
68     requires_update_ = requires_update;
69   }
70 
71  private:
72   int pairing_status_changed_count_ = 0;
73   int update_required_changed_count_ = 0;
74   bool requires_update_ = false;
75 
76   DISALLOW_COPY_AND_ASSIGN(TestBaseObserver);
77 };
78 
79 }  // namespace
80 
81 class DetachableBaseHandlerTest : public testing::Test {
82  public:
83   DetachableBaseHandlerTest() = default;
84   ~DetachableBaseHandlerTest() override = default;
85 
86   // testing::Test:
SetUp()87   void SetUp() override {
88     chromeos::HammerdClient::InitializeFake();
89     hammerd_client_ = chromeos::FakeHammerdClient::Get();
90 
91     chromeos::PowerManagerClient::InitializeFake();
92     chromeos::FakePowerManagerClient::Get()->SetTabletMode(
93         chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
94 
95     default_user_ = CreateUser("user_1@foo.bar", "111111", UserType::kNormal);
96 
97     DetachableBaseHandler::RegisterPrefs(local_state_.registry());
98     handler_ = std::make_unique<DetachableBaseHandler>(&local_state_);
99     handler_->AddObserver(&detachable_base_observer_);
100   }
101 
TearDown()102   void TearDown() override {
103     handler_->RemoveObserver(&detachable_base_observer_);
104     handler_.reset();
105     hammerd_client_ = nullptr;
106     chromeos::PowerManagerClient::Shutdown();
107     chromeos::HammerdClient::Shutdown();
108   }
109 
110  protected:
111   // Simulates system events associated with the detachable base being switched.
ChangePairedBase(const std::vector<uint8_t> & base_id)112   void ChangePairedBase(const std::vector<uint8_t>& base_id) {
113     chromeos::FakePowerManagerClient::Get()->SetTabletMode(
114         chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
115     chromeos::FakePowerManagerClient::Get()->SetTabletMode(
116         chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
117     detachable_base_observer_.reset_pairing_status_changed_count();
118 
119     hammerd_client_->FirePairChallengeSucceededSignal(base_id);
120   }
121 
RestartHandler()122   void RestartHandler() {
123     handler_->RemoveObserver(&detachable_base_observer_);
124     handler_ = std::make_unique<DetachableBaseHandler>(&local_state_);
125     handler_->AddObserver(&detachable_base_observer_);
126   }
127 
128   chromeos::FakeHammerdClient* hammerd_client_ = nullptr;
129 
130   TestBaseObserver detachable_base_observer_;
131 
132   std::unique_ptr<DetachableBaseHandler> handler_;
133 
134   UserInfo default_user_;
135 
136  private:
137   base::test::TaskEnvironment task_environment_;
138 
139   TestingPrefServiceSimple local_state_;
140 
141   DISALLOW_COPY_AND_ASSIGN(DetachableBaseHandlerTest);
142 };
143 
TEST_F(DetachableBaseHandlerTest,NoDetachableBase)144 TEST_F(DetachableBaseHandlerTest, NoDetachableBase) {
145   // Run loop so the handler picks up initial power manager state.
146   base::RunLoop().RunUntilIdle();
147 
148   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
149   EXPECT_EQ(0, detachable_base_observer_.pairing_status_changed_count());
150   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
151 }
152 
TEST_F(DetachableBaseHandlerTest,TabletModeOnOnStartup)153 TEST_F(DetachableBaseHandlerTest, TabletModeOnOnStartup) {
154   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
155       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
156   RestartHandler();
157 
158   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
159       chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
160   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
161 
162   // Run loop so the handler picks up initial power manager state.
163   base::RunLoop().RunUntilIdle();
164 
165   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
166             handler_->GetPairingStatus());
167   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
168   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
169 }
170 
TEST_F(DetachableBaseHandlerTest,SuccessfullPairing)171 TEST_F(DetachableBaseHandlerTest, SuccessfullPairing) {
172   // Run loop so the handler picks up initial power manager state.
173   base::RunLoop().RunUntilIdle();
174 
175   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
176   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
177 
178   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
179             handler_->GetPairingStatus());
180   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
181   // The user should not be notified when they attach a base for the first time,
182   // so the first paired base should be reported as kAuthenticated rather than
183   // kAuthenticatedNotMatchingLastUsed.
184   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
185   detachable_base_observer_.reset_pairing_status_changed_count();
186 
187   // Assume the base has been detached when the device switches to tablet mode.
188   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
189       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
190   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
191   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
192   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
193   detachable_base_observer_.reset_pairing_status_changed_count();
194 
195   // When the device exits tablet mode again, the base should not be reported
196   // as paired until it's finished pairing.
197   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
198       chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
199   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
200   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
201 
202   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
203   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
204             handler_->GetPairingStatus());
205   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
206   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
207   detachable_base_observer_.reset_pairing_status_changed_count();
208 }
209 
TEST_F(DetachableBaseHandlerTest,DetachableBasePairingFailure)210 TEST_F(DetachableBaseHandlerTest, DetachableBasePairingFailure) {
211   // Run loop so the handler picks up initial power manager state.
212   base::RunLoop().RunUntilIdle();
213 
214   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
215   hammerd_client_->FirePairChallengeFailedSignal();
216 
217   EXPECT_EQ(DetachableBasePairingStatus::kNotAuthenticated,
218             handler_->GetPairingStatus());
219   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
220   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
221   detachable_base_observer_.reset_pairing_status_changed_count();
222 
223   // Assume the base has been detached when the device switches to tablet mode.
224   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
225       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
226   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
227   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
228   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
229   detachable_base_observer_.reset_pairing_status_changed_count();
230 }
231 
TEST_F(DetachableBaseHandlerTest,InvalidDetachableBase)232 TEST_F(DetachableBaseHandlerTest, InvalidDetachableBase) {
233   // Run loop so the handler picks up initial power manager state.
234   base::RunLoop().RunUntilIdle();
235 
236   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
237   hammerd_client_->FireInvalidBaseConnectedSignal();
238 
239   EXPECT_EQ(DetachableBasePairingStatus::kInvalidDevice,
240             handler_->GetPairingStatus());
241   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
242   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
243   detachable_base_observer_.reset_pairing_status_changed_count();
244 
245   // Assume the base has been detached when the device switches to tablet mode.
246   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
247       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
248   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
249   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
250   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
251   detachable_base_observer_.reset_pairing_status_changed_count();
252 }
253 
TEST_F(DetachableBaseHandlerTest,PairingSuccessDuringInit)254 TEST_F(DetachableBaseHandlerTest, PairingSuccessDuringInit) {
255   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
256 
257   // DetachableBaseHandler updates base pairing state only after it confirms the
258   // device is not in tablet mode.
259   EXPECT_EQ(0, detachable_base_observer_.pairing_status_changed_count());
260   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
261   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
262 
263   // Run loop so the callback for getting the initial power manager state gets
264   // run.
265   base::RunLoop().RunUntilIdle();
266 
267   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
268   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
269             handler_->GetPairingStatus());
270   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
271   detachable_base_observer_.reset_pairing_status_changed_count();
272 }
273 
TEST_F(DetachableBaseHandlerTest,PairingFailDuringInit)274 TEST_F(DetachableBaseHandlerTest, PairingFailDuringInit) {
275   hammerd_client_->FirePairChallengeFailedSignal();
276 
277   // DetachableBaseHandler updates base pairing state only after it confirms the
278   // device is not in tablet mode.
279   EXPECT_EQ(0, detachable_base_observer_.pairing_status_changed_count());
280   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
281   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
282 
283   // Run loop so the callback for getting the initial power manager state gets
284   // run.
285   base::RunLoop().RunUntilIdle();
286 
287   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
288   EXPECT_EQ(DetachableBasePairingStatus::kNotAuthenticated,
289             handler_->GetPairingStatus());
290   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
291   detachable_base_observer_.reset_pairing_status_changed_count();
292 }
293 
TEST_F(DetachableBaseHandlerTest,InvalidDeviceDuringInit)294 TEST_F(DetachableBaseHandlerTest, InvalidDeviceDuringInit) {
295   hammerd_client_->FireInvalidBaseConnectedSignal();
296 
297   // DetachableBaseHandler updates base pairing state only after it confirms the
298   // device is not in tablet mode.
299   EXPECT_EQ(0, detachable_base_observer_.pairing_status_changed_count());
300   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
301   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
302 
303   // Run loop so the callback for getting the initial power manager state gets
304   // run.
305   base::RunLoop().RunUntilIdle();
306 
307   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
308   EXPECT_EQ(DetachableBasePairingStatus::kInvalidDevice,
309             handler_->GetPairingStatus());
310   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
311   detachable_base_observer_.reset_pairing_status_changed_count();
312 }
313 
TEST_F(DetachableBaseHandlerTest,TabletModeTurnedOnDuringHandlerInit)314 TEST_F(DetachableBaseHandlerTest, TabletModeTurnedOnDuringHandlerInit) {
315   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
316   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
317       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
318 
319   // Run loop so the callback for getting the initial power manager state gets
320   // run.
321   base::RunLoop().RunUntilIdle();
322 
323   EXPECT_EQ(0, detachable_base_observer_.pairing_status_changed_count());
324   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
325   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
326 }
327 
TEST_F(DetachableBaseHandlerTest,DetachableBaseChangeDetection)328 TEST_F(DetachableBaseHandlerTest, DetachableBaseChangeDetection) {
329   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
330       chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
331   // Run loop so the callback for getting the initial power manager state gets
332   // run.
333   base::RunLoop().RunUntilIdle();
334   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
335 
336   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
337             handler_->GetPairingStatus());
338   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
339   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
340   detachable_base_observer_.reset_pairing_status_changed_count();
341 
342   // Set the current base as last used by the user.
343   handler_->SetPairedBaseAsLastUsedByUser(default_user_);
344 
345   // Simulate the paired base change.
346   ChangePairedBase({0x04, 0x05, 0x06, 0x07});
347 
348   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
349             handler_->GetPairingStatus());
350   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
351   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
352   detachable_base_observer_.reset_pairing_status_changed_count();
353 
354   // Switch back to last used base.
355   ChangePairedBase({0x01, 0x02, 0x03, 0x04});
356 
357   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
358             handler_->GetPairingStatus());
359   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
360   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
361   detachable_base_observer_.reset_pairing_status_changed_count();
362 
363   // The last used base should be preserved if the detachable base handler is
364   // restarted after the last used base was set.
365   RestartHandler();
366   base::RunLoop().RunUntilIdle();
367 
368   hammerd_client_->FirePairChallengeSucceededSignal({0x04, 0x05, 0x06, 0x07});
369 
370   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
371             handler_->GetPairingStatus());
372   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
373   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
374   detachable_base_observer_.reset_pairing_status_changed_count();
375 }
376 
TEST_F(DetachableBaseHandlerTest,MultiUser)377 TEST_F(DetachableBaseHandlerTest, MultiUser) {
378   // Assume the user_1 has a last used base.
379   base::RunLoop().RunUntilIdle();
380   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
381   handler_->SetPairedBaseAsLastUsedByUser(default_user_);
382   detachable_base_observer_.reset_pairing_status_changed_count();
383 
384   // Restart the handler, so it's initialized with the previously set up prefs
385   // state.
386   RestartHandler();
387   base::RunLoop().RunUntilIdle();
388 
389   const UserInfo second_user =
390       CreateUser("user_2@foo.bar", "222222", UserType::kNormal);
391 
392   EXPECT_EQ(DetachableBasePairingStatus::kNone, handler_->GetPairingStatus());
393   EXPECT_EQ(0, detachable_base_observer_.pairing_status_changed_count());
394   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
395   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
396 
397   // Pair a detachable base different than the one used by user_1.
398   hammerd_client_->FirePairChallengeSucceededSignal({0x04, 0x05, 0x06, 0x07});
399 
400   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
401             handler_->GetPairingStatus());
402   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
403   // The base for user_1 has changed.
404   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
405   // User 2 has not used a detachable base yet - the base should be reported as
406   // matching last used base.
407   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
408   detachable_base_observer_.reset_pairing_status_changed_count();
409 
410   // Set the last used detachable base for user 2, and pair the initial base.
411   handler_->SetPairedBaseAsLastUsedByUser(second_user);
412 
413   ChangePairedBase({0x01, 0x02, 0x03, 0x04});
414 
415   // This time, the second user should be notified the base has been changed.
416   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
417             handler_->GetPairingStatus());
418   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
419   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
420   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
421   detachable_base_observer_.reset_pairing_status_changed_count();
422 
423   // Set the base for user 2 to the current one.
424   handler_->SetPairedBaseAsLastUsedByUser(second_user);
425 
426   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
427 
428   // When the base is paired next time, it should be considered authenticated
429   // for both users.
430   ChangePairedBase({0x01, 0x02, 0x03, 0x04});
431 
432   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
433             handler_->GetPairingStatus());
434   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
435   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
436   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
437   detachable_base_observer_.reset_pairing_status_changed_count();
438 }
439 
TEST_F(DetachableBaseHandlerTest,SwitchToNonAuthenticatedBase)440 TEST_F(DetachableBaseHandlerTest, SwitchToNonAuthenticatedBase) {
441   // Run loop so the handler picks up initial power manager state.
442   base::RunLoop().RunUntilIdle();
443 
444   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
445   handler_->SetPairedBaseAsLastUsedByUser(default_user_);
446   detachable_base_observer_.reset_pairing_status_changed_count();
447 
448   // Switch to non-trusted base, and verify it's reported as such regardless
449   // of whether the user had previously used a detachable base.
450   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
451       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
452   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
453       chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
454   detachable_base_observer_.reset_pairing_status_changed_count();
455 
456   hammerd_client_->FirePairChallengeFailedSignal();
457 
458   const UserInfo second_user =
459       CreateUser("user_2@foo.bar", "222222", UserType::kNormal);
460 
461   EXPECT_EQ(DetachableBasePairingStatus::kNotAuthenticated,
462             handler_->GetPairingStatus());
463   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
464   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
465   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
466   detachable_base_observer_.reset_pairing_status_changed_count();
467 }
468 
TEST_F(DetachableBaseHandlerTest,SwitchToInvalidBase)469 TEST_F(DetachableBaseHandlerTest, SwitchToInvalidBase) {
470   // Run loop so the handler picks up initial power manager state.
471   base::RunLoop().RunUntilIdle();
472 
473   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
474   handler_->SetPairedBaseAsLastUsedByUser(default_user_);
475   detachable_base_observer_.reset_pairing_status_changed_count();
476 
477   // Switch to an invalid base, and verify it's reported as such regardless
478   // of whether the user had previously used a base.
479   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
480       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
481   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
482       chromeos::PowerManagerClient::TabletMode::OFF, base::TimeTicks());
483   detachable_base_observer_.reset_pairing_status_changed_count();
484 
485   hammerd_client_->FireInvalidBaseConnectedSignal();
486 
487   const UserInfo second_user =
488       CreateUser("user_2@foo.bar", "222222", UserType::kNormal);
489 
490   EXPECT_EQ(DetachableBasePairingStatus::kInvalidDevice,
491             handler_->GetPairingStatus());
492   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
493   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
494   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
495   detachable_base_observer_.reset_pairing_status_changed_count();
496 }
497 
TEST_F(DetachableBaseHandlerTest,RemoveUserData)498 TEST_F(DetachableBaseHandlerTest, RemoveUserData) {
499   const UserInfo second_user =
500       CreateUser("user_2@foo.bar", "222222", UserType::kNormal);
501 
502   // Assume the user_1 has a last used base.
503   base::RunLoop().RunUntilIdle();
504   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
505   handler_->SetPairedBaseAsLastUsedByUser(default_user_);
506   handler_->SetPairedBaseAsLastUsedByUser(second_user);
507   detachable_base_observer_.reset_pairing_status_changed_count();
508 
509   ChangePairedBase({0x04, 0x05, 0x06});
510 
511   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
512             handler_->GetPairingStatus());
513   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
514   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
515   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
516   detachable_base_observer_.reset_pairing_status_changed_count();
517 
518   // Remove the data for user_2, and verify that the paired base is reported
519   // as authenticated when the paired base changes again.
520   handler_->RemoveUserData(second_user);
521   ChangePairedBase({0x07, 0x08, 0x09});
522 
523   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
524             handler_->GetPairingStatus());
525   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
526   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
527   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
528   detachable_base_observer_.reset_pairing_status_changed_count();
529 
530   // Verify that paired base will be properly set again for the previously
531   // removed user.
532   handler_->SetPairedBaseAsLastUsedByUser(second_user);
533   ChangePairedBase({0x01, 0x02, 0x03, 0x04});
534 
535   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
536             handler_->GetPairingStatus());
537   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
538   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(default_user_));
539   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(second_user));
540   detachable_base_observer_.reset_pairing_status_changed_count();
541 }
542 
TEST_F(DetachableBaseHandlerTest,EphemeralUser)543 TEST_F(DetachableBaseHandlerTest, EphemeralUser) {
544   base::RunLoop().RunUntilIdle();
545 
546   const UserInfo ephemeral_user =
547       CreateUser("user_3@foo.bar", "333333", UserType::kEphemeral);
548   hammerd_client_->FirePairChallengeSucceededSignal({0x01, 0x02, 0x03, 0x04});
549   handler_->SetPairedBaseAsLastUsedByUser(ephemeral_user);
550   detachable_base_observer_.reset_pairing_status_changed_count();
551 
552   ChangePairedBase({0x04, 0x05, 0x06});
553 
554   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
555             handler_->GetPairingStatus());
556   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
557   EXPECT_FALSE(handler_->PairedBaseMatchesLastUsedByUser(ephemeral_user));
558   detachable_base_observer_.reset_pairing_status_changed_count();
559 
560   ChangePairedBase({0x01, 0x02, 0x03, 0x04});
561 
562   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
563             handler_->GetPairingStatus());
564   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
565   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(ephemeral_user));
566   detachable_base_observer_.reset_pairing_status_changed_count();
567 
568   // Verify that the information about the last used base gets lost if the
569   // detachable base handler is reset (given that the info was saved for an
570   // ephemeral user).
571   RestartHandler();
572   base::RunLoop().RunUntilIdle();
573   hammerd_client_->FirePairChallengeSucceededSignal({0x04, 0x05, 0x06, 0x07});
574 
575   EXPECT_EQ(DetachableBasePairingStatus::kAuthenticated,
576             handler_->GetPairingStatus());
577   EXPECT_EQ(1, detachable_base_observer_.pairing_status_changed_count());
578   EXPECT_TRUE(handler_->PairedBaseMatchesLastUsedByUser(ephemeral_user));
579   detachable_base_observer_.reset_pairing_status_changed_count();
580 }
581 
TEST_F(DetachableBaseHandlerTest,NotifyObserversWhenBaseUpdateRequired)582 TEST_F(DetachableBaseHandlerTest, NotifyObserversWhenBaseUpdateRequired) {
583   hammerd_client_->FireBaseFirmwareNeedUpdateSignal();
584   EXPECT_EQ(1, detachable_base_observer_.update_required_changed_count());
585   EXPECT_TRUE(detachable_base_observer_.requires_update());
586 
587   hammerd_client_->FireBaseFirmwareUpdateSucceededSignal();
588   EXPECT_EQ(2, detachable_base_observer_.update_required_changed_count());
589   EXPECT_FALSE(detachable_base_observer_.requires_update());
590 }
591 
TEST_F(DetachableBaseHandlerTest,NotifyNoUpdateRequiredOnBaseDetach)592 TEST_F(DetachableBaseHandlerTest, NotifyNoUpdateRequiredOnBaseDetach) {
593   hammerd_client_->FireBaseFirmwareNeedUpdateSignal();
594   EXPECT_EQ(1, detachable_base_observer_.update_required_changed_count());
595   EXPECT_TRUE(detachable_base_observer_.requires_update());
596 
597   chromeos::FakePowerManagerClient::Get()->SetTabletMode(
598       chromeos::PowerManagerClient::TabletMode::ON, base::TimeTicks());
599   EXPECT_EQ(2, detachable_base_observer_.update_required_changed_count());
600   EXPECT_FALSE(detachable_base_observer_.requires_update());
601 }
602 
603 }  // namespace ash
604