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