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