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 26namespace chromeos { 27 28namespace { 29 30const char* kTestOwner = "test-owner@example.com"; 31const char* kTestNonOwner = "test-user1@example.com"; 32 33const 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. 45class 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 60struct PrefTest { 61 const char* pref_name; 62 bool owner_only; 63 bool indicator; 64}; 65 66const 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 82class 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 263IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_SharedOptions) { 264 RegisterUser(kTestOwner); 265 RegisterUser(kTestNonOwner); 266 StartupUtils::MarkOobeCompleted(); 267} 268 269IN_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 290IN_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.) 301IN_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 361IN_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.) 372IN_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