shared_options_browsertest.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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/basictypes.h"
6#include "base/compiler_specific.h"
7#include "base/prefs/pref_service.h"
8#include "base/strings/stringprintf.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/login/users/user_manager.h"
13#include "chrome/browser/chromeos/settings/cros_settings.h"
14#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/browser_commands.h"
17#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/common/pref_names.h"
19#include "chrome/test/base/ui_test_utils.h"
20#include "chromeos/settings/cros_settings_names.h"
21#include "content/public/browser/web_contents.h"
22#include "content/public/test/browser_test_utils.h"
23#include "content/public/test/test_utils.h"
24
25namespace chromeos {
26
27namespace {
28
29const char* kTestOwner = "test-owner@example.com";
30const char* kTestNonOwner = "test-user1@example.com";
31
32const char* kKnownSettings[] = {
33  kDeviceOwner,
34  kAccountsPrefAllowGuest,
35  kAccountsPrefAllowNewUser,
36  kAccountsPrefDeviceLocalAccounts,
37  kAccountsPrefShowUserNamesOnSignIn,
38  kAccountsPrefSupervisedUsersEnabled,
39};
40
41// Stub settings provider that only handles the settings we need to control.
42// StubCrosSettingsProvider handles more settings but leaves many of them unset
43// which the Settings page doesn't expect.
44class StubAccountSettingsProvider : public StubCrosSettingsProvider {
45 public:
46  StubAccountSettingsProvider() {
47  }
48
49  virtual ~StubAccountSettingsProvider() {
50  }
51
52  // StubCrosSettingsProvider implementation.
53  virtual bool HandlesSetting(const std::string& path) const OVERRIDE {
54    const char** end = kKnownSettings + arraysize(kKnownSettings);
55    return std::find(kKnownSettings, end, path) != end;
56  }
57};
58
59struct PrefTest {
60  const char* pref_name;
61  bool owner_only;
62  bool indicator;
63};
64
65const PrefTest kPrefTests[] = {
66  { kSystemTimezone, false, false },
67  { prefs::kUse24HourClock, false, false },
68  { kAttestationForContentProtectionEnabled, true, true },
69  { kAccountsPrefAllowGuest, true, false },
70  { kAccountsPrefAllowNewUser, true, false },
71  { kAccountsPrefShowUserNamesOnSignIn, true, false },
72  { kAccountsPrefSupervisedUsersEnabled, true, false },
73#if defined(GOOGLE_CHROME_BUILD)
74  { kStatsReportingPref, true, true },
75  { prefs::kSpellCheckUseSpellingService, false, false },
76#endif
77};
78
79}  // namespace
80
81class SharedOptionsTest : public LoginManagerTest {
82 public:
83  SharedOptionsTest()
84    : LoginManagerTest(false),
85      device_settings_provider_(NULL) {
86    stub_settings_provider_.Set(kDeviceOwner, base::StringValue(kTestOwner));
87  }
88
89  virtual ~SharedOptionsTest() {
90  }
91
92  virtual void SetUpOnMainThread() OVERRIDE {
93    LoginManagerTest::SetUpOnMainThread();
94
95    CrosSettings* settings = CrosSettings::Get();
96
97    // Add the stub settings provider, moving the device settings provider
98    // behind it so our stub takes precedence.
99    device_settings_provider_ = settings->GetProvider(kDeviceOwner);
100    settings->RemoveSettingsProvider(device_settings_provider_);
101    settings->AddSettingsProvider(&stub_settings_provider_);
102    settings->AddSettingsProvider(device_settings_provider_);
103  }
104
105  virtual void CleanUpOnMainThread() OVERRIDE {
106    CrosSettings* settings = CrosSettings::Get();
107    settings->RemoveSettingsProvider(&stub_settings_provider_);
108    LoginManagerTest::CleanUpOnMainThread();
109  }
110
111 protected:
112  void CheckOptionsUI(const User* user, bool is_owner, bool is_primary) {
113    Browser* browser = CreateBrowserForUser(user);
114    content::WebContents* contents =
115        browser->tab_strip_model()->GetActiveWebContents();
116
117    for (size_t i = 0; i < sizeof(kPrefTests) / sizeof(kPrefTests[0]); i++) {
118      CheckPreference(contents,
119                      kPrefTests[i].pref_name,
120                      !is_owner && kPrefTests[i].owner_only,
121                      !is_owner && kPrefTests[i].indicator ? "owner" :
122                                                             std::string());
123    }
124    CheckBanner(contents, is_primary);
125    CheckSharedSections(contents, is_primary);
126    CheckAccountsOverlay(contents, is_owner);
127  }
128
129  // Creates a browser and navigates to the Settings page.
130  Browser* CreateBrowserForUser(const User* user) {
131    Profile* profile = UserManager::Get()->GetProfileByUser(user);
132    profile->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
133                                   user->email());
134
135    ui_test_utils::BrowserAddedObserver observer;
136    Browser* browser = CreateBrowser(profile);
137    observer.WaitForSingleNewBrowser();
138
139    ui_test_utils::NavigateToURL(browser,
140                                 GURL("chrome://settings-frame"));
141    return browser;
142  }
143
144  // Verifies a preference's disabled state and controlled-by indicator.
145  void CheckPreference(content::WebContents* contents,
146                       std::string pref_name,
147                       bool disabled,
148                       std::string controlled_by) {
149    bool success;
150    std::string js_expression = base::StringPrintf(
151        "var prefSelector = '[pref=\"%s\"]';"
152        "var controlledBy = '%s';"
153        "var input = document.querySelector("
154        "    'input' + prefSelector + ', select' + prefSelector);"
155        "var success = false;"
156        "if (input) {"
157        "  success = input.disabled == %d;"
158        "  var indicator = document.querySelector(input.tagName +"
159        "      prefSelector + ' + span span.controlled-setting-indicator');"
160        "  if (controlledBy) {"
161        "    success = success && indicator &&"
162        "              indicator.getAttribute('controlled-by') == controlledBy;"
163        "  } else {"
164        "    success = success && (!indicator ||"
165        "              !indicator.hasAttribute('controlled-by') ||"
166        "              indicator.getAttribute('controlled-by') == '')"
167        "  }"
168        "}"
169        "window.domAutomationController.send(!!success);",
170        pref_name.c_str(), controlled_by.c_str(), disabled);
171    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
172        contents, js_expression, &success));
173    EXPECT_TRUE(success);
174  }
175
176  // Verifies a checkbox's disabled state, controlled-by indicator and value.
177  void CheckBooleanPreference(content::WebContents* contents,
178                              std::string pref_name,
179                              bool disabled,
180                              std::string controlled_by,
181                              bool expected_value) {
182    CheckPreference(contents, pref_name, disabled, controlled_by);
183    bool actual_value;
184    std::string js_expression = base::StringPrintf(
185        "window.domAutomationController.send(document.querySelector('"
186        "    input[type=\"checkbox\"][pref=\"%s\"]').checked);",
187        pref_name.c_str());
188    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
189        contents, js_expression, &actual_value));
190    EXPECT_EQ(expected_value, actual_value);
191  }
192
193  // Verifies that the shared settings banner is visible only for
194  // secondary users.
195  void CheckBanner(content::WebContents* contents,
196                   bool is_primary) {
197    bool banner_visible;
198    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
199        contents,
200        "var e = $('secondary-user-banner');"
201        "window.domAutomationController.send(e && !e.hidden);",
202        &banner_visible));
203    EXPECT_EQ(!is_primary, banner_visible);
204  }
205
206  // Verifies that sections of shared settings have the appropriate indicator.
207  void CheckSharedSections(content::WebContents* contents,
208                           bool is_primary) {
209    // This only applies to the Internet options section.
210    std::string controlled_by;
211    ASSERT_TRUE(content::ExecuteScriptAndExtractString(
212        contents,
213        "var e = document.querySelector("
214        "    '#network-section-header span.controlled-setting-indicator');"
215        "if (!e || !e.getAttribute('controlled-by')) {"
216        "  window.domAutomationController.send('');"
217        "} else {"
218        "  window.domAutomationController.send("
219        "      e.getAttribute('controlled-by'));"
220        "}",
221        &controlled_by));
222    EXPECT_EQ(!is_primary ? "shared" : std::string(), controlled_by);
223  }
224
225  // Checks the Accounts header and non-checkbox inputs.
226  void CheckAccountsOverlay(content::WebContents* contents, bool is_owner) {
227    // Set cros.accounts.allowGuest to false so we can test the accounts list.
228    // This has to be done after the PRE_* test or we can't add the owner.
229    stub_settings_provider_.Set(
230        kAccountsPrefAllowNewUser, base::FundamentalValue(false));
231
232    bool success;
233    std::string js_expression = base::StringPrintf(
234        "var controlled = %d;"
235        "var warning = $('ownerOnlyWarning');"
236        "var userList = $('userList');"
237        "var input = $('userNameEdit');"
238        "var success;"
239        "if (controlled)"
240        "  success = warning && !warning.hidden && userList.disabled &&"
241        "            input.disabled;"
242        "else"
243        "  success = (!warning || warning.hidden) && !userList.disabled &&"
244        "            !input.disabled;"
245        "window.domAutomationController.send(!!success);",
246        !is_owner);
247    ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
248        contents, js_expression, &success));
249    EXPECT_TRUE(success) << "Accounts overlay incorrect for " <<
250        (is_owner ? "owner." : "non-owner.");
251  }
252
253  StubAccountSettingsProvider stub_settings_provider_;
254  CrosSettingsProvider* device_settings_provider_;
255
256 private:
257  DISALLOW_COPY_AND_ASSIGN(SharedOptionsTest);
258};
259
260IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_SharedOptions) {
261  RegisterUser(kTestOwner);
262  RegisterUser(kTestNonOwner);
263  StartupUtils::MarkOobeCompleted();
264}
265
266IN_PROC_BROWSER_TEST_F(SharedOptionsTest, SharedOptions) {
267  // Log in the owner first, then add a secondary user.
268  LoginUser(kTestOwner);
269  UserAddingScreen::Get()->Start();
270  content::RunAllPendingInMessageLoop();
271  AddUser(kTestNonOwner);
272
273  UserManager* manager = UserManager::Get();
274  ASSERT_EQ(2u, manager->GetLoggedInUsers().size());
275  {
276    SCOPED_TRACE("Checking settings for owner, primary user.");
277    CheckOptionsUI(manager->FindUser(manager->GetOwnerEmail()), true, true);
278  }
279  {
280    SCOPED_TRACE("Checking settings for non-owner, secondary user.");
281    CheckOptionsUI(manager->FindUser(kTestNonOwner), false, false);
282  }
283  // TODO(michaelpg): Add tests for non-primary owner and primary non-owner
284  // when the owner-only multiprofile restriction is removed, probably M38.
285}
286
287IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_ScreenLockPreference) {
288  RegisterUser(kTestOwner);
289  RegisterUser(kTestNonOwner);
290  StartupUtils::MarkOobeCompleted();
291}
292
293// Tests that a shared setting indicator appears for the auto-lock setting
294// when the user has the checkbox unselected but another user has enabled
295// auto-lock. (The checkbox is unset if the user's preference is false,
296// but if any other signed-in user has enabled this preference, the shared
297// setting indicator explains this.)
298IN_PROC_BROWSER_TEST_F(SharedOptionsTest, ScreenLockPreference) {
299  LoginUser(kTestOwner);
300  UserAddingScreen::Get()->Start();
301  content::RunAllPendingInMessageLoop();
302  AddUser(kTestNonOwner);
303
304  UserManager* manager = UserManager::Get();
305  const User* user1 = manager->FindUser(kTestOwner);
306  const User* user2 = manager->FindUser(kTestNonOwner);
307
308  PrefService* prefs1 = manager->GetProfileByUser(user1)->GetPrefs();
309  PrefService* prefs2 = manager->GetProfileByUser(user2)->GetPrefs();
310  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, false);
311  prefs2->SetBoolean(prefs::kEnableAutoScreenLock, false);
312
313  Browser* browser1 = CreateBrowserForUser(user1);
314  Browser* browser2 = CreateBrowserForUser(user2);
315  content::WebContents* contents1 =
316      browser1->tab_strip_model()->GetActiveWebContents();
317  content::WebContents* contents2 =
318      browser2->tab_strip_model()->GetActiveWebContents();
319
320  bool disabled = false;
321  bool expected_value;
322  std::string empty_controlled;
323  std::string shared_controlled("shared");
324
325  // First test case: secondary user dependent on primary user.
326  {
327    SCOPED_TRACE("Screen lock false for both users");
328    expected_value = false;
329    CheckBooleanPreference(contents1, prefs::kEnableAutoScreenLock, disabled,
330                           empty_controlled, expected_value);
331    CheckBooleanPreference(contents2, prefs::kEnableAutoScreenLock, disabled,
332                           empty_controlled, expected_value);
333  }
334  // Set the preference to true for the primary user and check that the value
335  // changes appropriately.
336  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, true);
337  {
338    SCOPED_TRACE("Screen lock true for primary user");
339    expected_value = true;
340    CheckBooleanPreference(contents1, prefs::kEnableAutoScreenLock, disabled,
341                           empty_controlled, expected_value);
342  }
343  // Reload the secondary user's browser to see the updated controlled-by
344  // indicator. Also reload the primary user's to make sure the setting still
345  // starts out correctly.
346  chrome::Reload(browser1, CURRENT_TAB);
347  chrome::Reload(browser2, CURRENT_TAB);
348  content::WaitForLoadStop(contents1);
349  content::WaitForLoadStop(contents2);
350  {
351    SCOPED_TRACE("Screen lock true for primary user, false for secondary user");
352    expected_value = true;
353    CheckBooleanPreference(contents1, prefs::kEnableAutoScreenLock, disabled,
354                           empty_controlled, expected_value);
355    expected_value = false;
356    CheckBooleanPreference(contents2, prefs::kEnableAutoScreenLock, disabled,
357                           shared_controlled, expected_value);
358  }
359  // Set the preference to true for the secondary user and check that the
360  // indicator disappears.
361  prefs2->SetBoolean(prefs::kEnableAutoScreenLock, true);
362  {
363    SCOPED_TRACE("Screen lock true for secondary user");
364    expected_value = true;
365    CheckBooleanPreference(contents2, prefs::kEnableAutoScreenLock, disabled,
366                           empty_controlled, expected_value);
367  }
368
369  // Second test case: primary user dependent on secondary user.
370  chrome::Reload(browser1, CURRENT_TAB);
371  chrome::Reload(browser2, CURRENT_TAB);
372  content::WaitForLoadStop(contents1);
373  content::WaitForLoadStop(contents2);
374  {
375    SCOPED_TRACE("Screen lock true for both users");
376    expected_value = true;
377    CheckBooleanPreference(contents1, prefs::kEnableAutoScreenLock, disabled,
378                           empty_controlled, expected_value);
379    CheckBooleanPreference(contents2, prefs::kEnableAutoScreenLock, disabled,
380                           empty_controlled, expected_value);
381  }
382  // Set the preference to false for the primary user and check that the
383  // value changes correctly.
384  prefs1->SetBoolean(prefs::kEnableAutoScreenLock, false);
385  {
386    SCOPED_TRACE("Screen lock false for primary user");
387    expected_value = false;
388    CheckBooleanPreference(contents1, prefs::kEnableAutoScreenLock, disabled,
389                           shared_controlled, expected_value);
390  }
391  // The primary user should now see a shared setting indicator.
392  chrome::Reload(browser1, CURRENT_TAB);
393  chrome::Reload(browser2, CURRENT_TAB);
394  content::WaitForLoadStop(contents1);
395  content::WaitForLoadStop(contents2);
396  {
397    SCOPED_TRACE("Screen lock false for primary user, true for secondary user");
398    expected_value = false;
399    CheckBooleanPreference(contents1, prefs::kEnableAutoScreenLock, disabled,
400                           shared_controlled, expected_value);
401    expected_value = true;
402    CheckBooleanPreference(contents2, prefs::kEnableAutoScreenLock, disabled,
403                           empty_controlled, expected_value);
404  }
405}
406
407}  // namespace chromeos
408