1// Copyright 2014 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 "base/command_line.h"
6#include "base/macros.h"
7#include "base/run_loop.h"
8#include "base/values.h"
9#include "chrome/browser/chromeos/login/login_manager_test.h"
10#include "chrome/browser/chromeos/login/startup_utils.h"
11#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
12#include "chrome/browser/chromeos/profiles/profile_helper.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/signin/easy_unlock_service.h"
16#include "chrome/browser/ui/browser.h"
17#include "chrome/common/extensions/extension_constants.h"
18#include "chrome/test/base/in_process_browser_test.h"
19#include "chromeos/dbus/dbus_thread_manager.h"
20#include "chromeos/dbus/fake_power_manager_client.h"
21#include "components/policy/core/browser/browser_policy_connector.h"
22#include "components/policy/core/common/mock_configuration_policy_provider.h"
23#include "components/policy/core/common/policy_map.h"
24#include "components/policy/core/common/policy_types.h"
25#include "components/user_manager/user_manager.h"
26#include "content/public/common/content_switches.h"
27#include "device/bluetooth/bluetooth_adapter_factory.h"
28#include "device/bluetooth/test/mock_bluetooth_adapter.h"
29#include "extensions/browser/extension_system.h"
30#include "policy/policy_constants.h"
31#include "testing/gmock/include/gmock/gmock.h"
32
33using chromeos::DBusThreadManagerSetter;
34using chromeos::FakePowerManagerClient;
35using chromeos::PowerManagerClient;
36using chromeos::ProfileHelper;
37using chromeos::LoginManagerTest;
38using chromeos::StartupUtils;
39using chromeos::UserAddingScreen;
40using user_manager::UserManager;
41using device::MockBluetoothAdapter;
42using testing::_;
43using testing::Return;
44
45namespace {
46
47const char kTestUser1[] = "primary.user@example.com";
48const char kTestUser2[] = "secondary.user@example.com";
49
50#if defined(GOOGLE_CHROME_BUILD)
51bool HasEasyUnlockAppForProfile(Profile* profile) {
52  extensions::ExtensionSystem* extension_system =
53      extensions::ExtensionSystem::Get(profile);
54  ExtensionService* extension_service = extension_system->extension_service();
55  return !!extension_service->GetExtensionById(
56      extension_misc::kEasyUnlockAppId, false);
57}
58#endif
59
60void SetUpBluetoothMock(
61    scoped_refptr<testing::NiceMock<MockBluetoothAdapter> > mock_adapter,
62    bool is_present) {
63  device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter);
64
65  EXPECT_CALL(*mock_adapter, IsPresent())
66      .WillRepeatedly(testing::Return(is_present));
67
68  // These functions are called from ash system tray. They are speculations of
69  // why flaky gmock errors are seen on bots.
70  EXPECT_CALL(*mock_adapter, IsPowered())
71      .WillRepeatedly(testing::Return(true));
72  EXPECT_CALL(*mock_adapter, GetDevices()).WillRepeatedly(
73      testing::Return(device::BluetoothAdapter::ConstDeviceList()));
74}
75
76}  // namespace
77
78class EasyUnlockServiceTest : public InProcessBrowserTest {
79 public:
80  EasyUnlockServiceTest() : is_bluetooth_adapter_present_(true) {}
81  virtual ~EasyUnlockServiceTest() {}
82
83  void SetEasyUnlockAllowedPolicy(bool allowed) {
84    policy::PolicyMap policy;
85    policy.Set(policy::key::kEasyUnlockAllowed,
86               policy::POLICY_LEVEL_MANDATORY,
87               policy::POLICY_SCOPE_USER,
88               new base::FundamentalValue(allowed),
89               NULL);
90    provider_.UpdateChromePolicy(policy);
91    base::RunLoop().RunUntilIdle();
92  }
93
94#if defined(GOOGLE_CHROME_BUILD)
95  bool HasEasyUnlockApp() const {
96    return HasEasyUnlockAppForProfile(profile());
97  }
98#endif
99
100  // InProcessBrowserTest:
101  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
102    EXPECT_CALL(provider_, IsInitializationComplete(_))
103        .WillRepeatedly(Return(true));
104    policy::BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
105
106    mock_adapter_ = new testing::NiceMock<MockBluetoothAdapter>();
107    SetUpBluetoothMock(mock_adapter_, is_bluetooth_adapter_present_);
108
109    scoped_ptr<DBusThreadManagerSetter> dbus_setter =
110        chromeos::DBusThreadManager::GetSetterForTesting();
111    power_manager_client_ = new FakePowerManagerClient;
112    dbus_setter->SetPowerManagerClient(
113        scoped_ptr<PowerManagerClient>(power_manager_client_));
114  }
115
116  Profile* profile() const { return browser()->profile(); }
117
118  EasyUnlockService* service() const {
119    return EasyUnlockService::Get(profile());
120  }
121
122  void set_is_bluetooth_adapter_present(bool is_present) {
123    is_bluetooth_adapter_present_ = is_present;
124  }
125
126  FakePowerManagerClient* power_manager_client() {
127    return power_manager_client_;
128  }
129
130 private:
131  policy::MockConfigurationPolicyProvider provider_;
132  scoped_refptr<testing::NiceMock<MockBluetoothAdapter> > mock_adapter_;
133  bool is_bluetooth_adapter_present_;
134  FakePowerManagerClient* power_manager_client_;
135
136  DISALLOW_COPY_AND_ASSIGN(EasyUnlockServiceTest);
137};
138
139IN_PROC_BROWSER_TEST_F(EasyUnlockServiceTest, NoFinchNoService) {
140  EXPECT_FALSE(service()->IsAllowed());
141#if defined(GOOGLE_CHROME_BUILD)
142  EXPECT_FALSE(HasEasyUnlockApp());
143#endif
144}
145
146class EasyUnlockServiceNoBluetoothTest : public EasyUnlockServiceTest {
147 public:
148  EasyUnlockServiceNoBluetoothTest() {}
149  virtual ~EasyUnlockServiceNoBluetoothTest() {}
150
151  // InProcessBrowserTest:
152  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
153    set_is_bluetooth_adapter_present(false);
154    EasyUnlockServiceTest::SetUpInProcessBrowserTestFixture();
155  }
156
157 private:
158  DISALLOW_COPY_AND_ASSIGN(EasyUnlockServiceNoBluetoothTest);
159};
160
161IN_PROC_BROWSER_TEST_F(EasyUnlockServiceNoBluetoothTest, NoService) {
162  EXPECT_FALSE(service()->IsAllowed());
163#if defined(GOOGLE_CHROME_BUILD)
164  EXPECT_FALSE(HasEasyUnlockApp());
165#endif
166}
167
168class EasyUnlockServiceFinchEnabledTest : public EasyUnlockServiceTest {
169 public:
170  EasyUnlockServiceFinchEnabledTest() {}
171  virtual ~EasyUnlockServiceFinchEnabledTest() {}
172
173  // InProcessBrowserTest:
174  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
175    command_line->AppendSwitchASCII(switches::kForceFieldTrials,
176                                    "EasyUnlock/Enable/");
177  }
178
179 private:
180  DISALLOW_COPY_AND_ASSIGN(EasyUnlockServiceFinchEnabledTest);
181};
182
183IN_PROC_BROWSER_TEST_F(EasyUnlockServiceFinchEnabledTest, Enabled) {
184  EXPECT_TRUE(service()->IsAllowed());
185#if defined(GOOGLE_CHROME_BUILD)
186  EXPECT_TRUE(HasEasyUnlockApp());
187#endif
188}
189
190#if defined(GOOGLE_CHROME_BUILD)
191IN_PROC_BROWSER_TEST_F(EasyUnlockServiceFinchEnabledTest, UnloadsOnSuspend) {
192  EXPECT_TRUE(HasEasyUnlockApp());
193  power_manager_client()->SendSuspendImminent();
194  EXPECT_FALSE(HasEasyUnlockApp());
195  power_manager_client()->SendSuspendDone();
196  EXPECT_TRUE(HasEasyUnlockApp());
197}
198#endif
199
200// Tests that policy can override finch to turn easy unlock off.
201IN_PROC_BROWSER_TEST_F(EasyUnlockServiceFinchEnabledTest, PolicyOveride) {
202  EXPECT_TRUE(service()->IsAllowed());
203#if defined(GOOGLE_CHROME_BUILD)
204  EXPECT_TRUE(HasEasyUnlockApp());
205#endif
206
207  // Overridden by policy.
208  SetEasyUnlockAllowedPolicy(false);
209  EXPECT_FALSE(service()->IsAllowed());
210#if defined(GOOGLE_CHROME_BUILD)
211  EXPECT_FALSE(HasEasyUnlockApp());
212#endif
213
214  SetEasyUnlockAllowedPolicy(true);
215  EXPECT_TRUE(service()->IsAllowed());
216#if defined(GOOGLE_CHROME_BUILD)
217  EXPECT_TRUE(HasEasyUnlockApp());
218#endif
219}
220
221class EasyUnlockServiceFinchDisabledTest : public EasyUnlockServiceTest {
222 public:
223  EasyUnlockServiceFinchDisabledTest() {}
224  virtual ~EasyUnlockServiceFinchDisabledTest() {}
225
226  // InProcessBrowserTest:
227  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
228    command_line->AppendSwitchASCII(switches::kForceFieldTrials,
229                                    "EasyUnlock/Disable/");
230  }
231
232 private:
233  DISALLOW_COPY_AND_ASSIGN(EasyUnlockServiceFinchDisabledTest);
234};
235
236// Tests that easy unlock is off when finch is disabled and policy overrides
237// finch.
238IN_PROC_BROWSER_TEST_F(EasyUnlockServiceFinchDisabledTest, PolicyOverride) {
239  // Finch is disabled.
240  EXPECT_FALSE(service()->IsAllowed());
241#if defined(GOOGLE_CHROME_BUILD)
242  EXPECT_FALSE(HasEasyUnlockApp());
243#endif
244
245  // Policy overrides finch and turns on Easy unlock.
246  SetEasyUnlockAllowedPolicy(true);
247  EXPECT_TRUE(service()->IsAllowed());
248#if defined(GOOGLE_CHROME_BUILD)
249  EXPECT_TRUE(HasEasyUnlockApp());
250#endif
251}
252
253class EasyUnlockServiceMultiProfileTest : public LoginManagerTest {
254 public:
255  EasyUnlockServiceMultiProfileTest() : LoginManagerTest(false) {}
256  virtual ~EasyUnlockServiceMultiProfileTest() {}
257
258  // InProcessBrowserTest:
259  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
260    LoginManagerTest::SetUpInProcessBrowserTestFixture();
261
262    mock_adapter_ = new testing::NiceMock<MockBluetoothAdapter>();
263    SetUpBluetoothMock(mock_adapter_, true);
264  }
265
266 private:
267  scoped_refptr<testing::NiceMock<MockBluetoothAdapter> > mock_adapter_;
268  DISALLOW_COPY_AND_ASSIGN(EasyUnlockServiceMultiProfileTest);
269};
270
271IN_PROC_BROWSER_TEST_F(EasyUnlockServiceMultiProfileTest,
272                       PRE_DisallowedOnSecondaryProfile) {
273  RegisterUser(kTestUser1);
274  RegisterUser(kTestUser2);
275  StartupUtils::MarkOobeCompleted();
276}
277
278IN_PROC_BROWSER_TEST_F(EasyUnlockServiceMultiProfileTest,
279                       DisallowedOnSecondaryProfile) {
280  LoginUser(kTestUser1);
281  chromeos::UserAddingScreen::Get()->Start();
282  base::RunLoop().RunUntilIdle();
283  AddUser(kTestUser2);
284  const user_manager::User* primary_user =
285      user_manager::UserManager::Get()->FindUser(kTestUser1);
286  const user_manager::User* secondary_user =
287      user_manager::UserManager::Get()->FindUser(kTestUser2);
288
289  Profile* primary_profile = ProfileHelper::Get()->GetProfileByUserIdHash(
290      primary_user->username_hash());
291  Profile* secondary_profile = ProfileHelper::Get()->GetProfileByUserIdHash(
292      secondary_user->username_hash());
293
294  EXPECT_TRUE(EasyUnlockService::Get(primary_profile)->IsAllowed());
295  EXPECT_FALSE(EasyUnlockService::Get(secondary_profile)->IsAllowed());
296#if defined(GOOGLE_CHROME_BUILD)
297  EXPECT_TRUE(HasEasyUnlockAppForProfile(primary_profile));
298  EXPECT_FALSE(HasEasyUnlockAppForProfile(secondary_profile));
299#endif
300}
301