1 // Copyright (c) 2012 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 "chrome/browser/ui/webui/options/preferences_browsertest.h" 6 7 #include <iostream> 8 #include <sstream> 9 10 #include "base/callback.h" 11 #include "base/json/json_reader.h" 12 #include "base/json/json_writer.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/prefs/pref_service.h" 15 #include "base/values.h" 16 #include "chrome/browser/chrome_notification_types.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/ui/browser.h" 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" 20 #include "chrome/common/pref_names.h" 21 #include "chrome/common/url_constants.h" 22 #include "chrome/test/base/ui_test_utils.h" 23 #include "components/policy/core/browser/browser_policy_connector.h" 24 #include "components/policy/core/common/external_data_fetcher.h" 25 #include "components/policy/core/common/policy_map.h" 26 #include "components/policy/core/common/policy_types.h" 27 #include "content/public/browser/notification_details.h" 28 #include "content/public/browser/notification_source.h" 29 #include "content/public/browser/render_view_host.h" 30 #include "content/public/browser/web_contents.h" 31 #include "content/public/test/browser_test_utils.h" 32 #include "policy/policy_constants.h" 33 #include "testing/gtest/include/gtest/gtest.h" 34 #include "url/gurl.h" 35 36 #if defined(OS_CHROMEOS) 37 #include "base/strings/stringprintf.h" 38 #include "chrome/browser/browser_process.h" 39 #include "chrome/browser/chromeos/net/proxy_config_handler.h" 40 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" 41 #include "chrome/browser/chromeos/policy/stub_enterprise_install_attributes.h" 42 #include "chrome/browser/chromeos/proxy_cros_settings_parser.h" 43 #include "chrome/browser/chromeos/settings/cros_settings.h" 44 #include "chrome/browser/prefs/proxy_config_dictionary.h" 45 #include "chromeos/dbus/dbus_thread_manager.h" 46 #include "chromeos/dbus/shill_profile_client.h" 47 #include "chromeos/dbus/shill_service_client.h" 48 #include "chromeos/network/network_state.h" 49 #include "chromeos/network/network_state_handler.h" 50 #include "chromeos/settings/cros_settings_names.h" 51 #include "content/public/test/test_utils.h" 52 #include "third_party/cros_system_api/dbus/service_constants.h" 53 #endif 54 55 using testing::AllOf; 56 using testing::Mock; 57 using testing::Property; 58 using testing::Return; 59 using testing::_; 60 61 namespace base { 62 63 // Helper for using EXPECT_EQ() with base::Value. 64 bool operator==(const base::Value& first, const base::Value& second) { 65 return first.Equals(&second); 66 } 67 68 // Helper for pretty-printing the contents of base::Value in case of failures. 69 void PrintTo(const base::Value& value, std::ostream* stream) { 70 std::string json; 71 JSONWriter::Write(&value, &json); 72 *stream << json; 73 } 74 75 } // namespace base 76 77 // Googlemock matcher for base::Value. 78 MATCHER_P(EqualsValue, expected, "") { 79 return arg && arg->Equals(expected); 80 } 81 82 PreferencesBrowserTest::PreferencesBrowserTest() { 83 } 84 85 PreferencesBrowserTest::~PreferencesBrowserTest() { 86 } 87 88 // Navigates to the settings page, causing the JavaScript pref handling code to 89 // load and injects JavaScript testing code. 90 void PreferencesBrowserTest::SetUpOnMainThread() { 91 ui_test_utils::NavigateToURL(browser(), 92 GURL(chrome::kChromeUISettingsFrameURL)); 93 SetUpPrefs(); 94 } 95 96 void PreferencesBrowserTest::SetUpPrefs() { 97 content::WebContents* web_contents = 98 browser()->tab_strip_model()->GetActiveWebContents(); 99 ASSERT_TRUE(web_contents); 100 render_view_host_ = web_contents->GetRenderViewHost(); 101 ASSERT_TRUE(render_view_host_); 102 pref_service_ = browser()->profile()->GetPrefs(); 103 pref_change_registrar_.Init(pref_service_); 104 ASSERT_TRUE(content::ExecuteScript(render_view_host_, 105 "function TestEnv() {" 106 " this.sentinelName_ = 'download.prompt_for_download';" 107 " this.prefs_ = [];" 108 " TestEnv.instance_ = this;" 109 "}" 110 "" 111 "TestEnv.handleEvent = function(event) {" 112 " var env = TestEnv.instance_;" 113 " var name = event.type;" 114 " env.removePrefListener_(name);" 115 " if (name == TestEnv.sentinelName_)" 116 " env.sentinelValue_ = event.value.value;" 117 " else" 118 " env.reply_[name] = event.value;" 119 " if (env.fetching_ && !--env.fetching_ ||" 120 " !env.fetching_ && name == env.sentinelName_) {" 121 " env.removePrefListeners_();" 122 " window.domAutomationController.send(JSON.stringify(env.reply_));" 123 " delete env.reply_;" 124 " }" 125 "};" 126 "" 127 "TestEnv.prototype = {" 128 " addPrefListener_: function(name) {" 129 " Preferences.getInstance().addEventListener(name," 130 " TestEnv.handleEvent);" 131 " }," 132 "" 133 " addPrefListeners_: function() {" 134 " for (var i in this.prefs_)" 135 " this.addPrefListener_(this.prefs_[i]);" 136 " }," 137 "" 138 " removePrefListener_: function(name) {" 139 " Preferences.getInstance().removeEventListener(name," 140 " TestEnv.handleEvent);" 141 " }," 142 "" 143 " removePrefListeners_: function() {" 144 " for (var i in this.prefs_)" 145 " this.removePrefListener_(this.prefs_[i]);" 146 " }," 147 "" 148 "" 149 " addPref: function(name) {" 150 " this.prefs_.push(name);" 151 " }," 152 "" 153 " setupAndReply: function() {" 154 " this.reply_ = {};" 155 " Preferences.instance_ = new Preferences();" 156 " this.addPref(this.sentinelName_);" 157 " this.fetching_ = this.prefs_.length;" 158 " this.addPrefListeners_();" 159 " Preferences.getInstance().initialize();" 160 " }," 161 "" 162 " runAndReply: function(test) {" 163 " this.reply_ = {};" 164 " this.addPrefListeners_();" 165 " test();" 166 " this.sentinelValue_ = !this.sentinelValue_;" 167 " Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_," 168 " true);" 169 " }," 170 "" 171 " startObserving: function() {" 172 " this.reply_ = {};" 173 " this.addPrefListeners_();" 174 " }," 175 "" 176 " finishObservingAndReply: function() {" 177 " this.sentinelValue_ = !this.sentinelValue_;" 178 " Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_," 179 " true);" 180 " }" 181 "};")); 182 } 183 184 // Forwards notifications received when pref values change in the backend. 185 void PreferencesBrowserTest::OnPreferenceChanged(const std::string& pref_name) { 186 OnCommit(pref_service_->FindPreference(pref_name.c_str())); 187 } 188 189 void PreferencesBrowserTest::SetUpInProcessBrowserTestFixture() { 190 // Sets up a mock policy provider for user and device policies. 191 EXPECT_CALL(policy_provider_, IsInitializationComplete(_)) 192 .WillRepeatedly(Return(true)); 193 policy::BrowserPolicyConnector::SetPolicyProviderForTesting( 194 &policy_provider_); 195 }; 196 197 void PreferencesBrowserTest::SetUserPolicies( 198 const std::vector<std::string>& names, 199 const std::vector<base::Value*>& values, 200 policy::PolicyLevel level) { 201 policy::PolicyMap map; 202 for (size_t i = 0; i < names.size(); ++i) { 203 map.Set(names[i], level, policy::POLICY_SCOPE_USER, 204 values[i]->DeepCopy(), NULL); 205 } 206 policy_provider_.UpdateChromePolicy(map); 207 } 208 209 void PreferencesBrowserTest::ClearUserPolicies() { 210 policy::PolicyMap empty_policy_map; 211 policy_provider_.UpdateChromePolicy(empty_policy_map); 212 } 213 214 void PreferencesBrowserTest::SetUserValues( 215 const std::vector<std::string>& names, 216 const std::vector<base::Value*>& values) { 217 for (size_t i = 0; i < names.size(); ++i) { 218 pref_service_->Set(names[i].c_str(), *values[i]); 219 } 220 } 221 222 void PreferencesBrowserTest::VerifyKeyValue(const base::DictionaryValue& dict, 223 const std::string& key, 224 const base::Value& expected) { 225 const base::Value* actual = NULL; 226 EXPECT_TRUE(dict.Get(key, &actual)) << "Was checking key: " << key; 227 if (actual) 228 EXPECT_EQ(expected, *actual) << "Was checking key: " << key; 229 } 230 231 void PreferencesBrowserTest::VerifyPref(const base::DictionaryValue* prefs, 232 const std::string& name, 233 const base::Value* value, 234 const std::string& controlledBy, 235 bool disabled, 236 bool uncommitted) { 237 const base::Value* pref = NULL; 238 const base::DictionaryValue* dict = NULL; 239 ASSERT_TRUE(prefs->GetWithoutPathExpansion(name, &pref)); 240 ASSERT_TRUE(pref->GetAsDictionary(&dict)); 241 VerifyKeyValue(*dict, "value", *value); 242 if (!controlledBy.empty()) 243 VerifyKeyValue(*dict, "controlledBy", base::StringValue(controlledBy)); 244 else 245 EXPECT_FALSE(dict->HasKey("controlledBy")); 246 247 if (disabled) 248 VerifyKeyValue(*dict, "disabled", base::FundamentalValue(true)); 249 else if (dict->HasKey("disabled")) 250 VerifyKeyValue(*dict, "disabled", base::FundamentalValue(false)); 251 252 if (uncommitted) 253 VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(true)); 254 else if (dict->HasKey("uncommitted")) 255 VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(false)); 256 } 257 258 void PreferencesBrowserTest::VerifyObservedPref(const std::string& json, 259 const std::string& name, 260 const base::Value* value, 261 const std::string& controlledBy, 262 bool disabled, 263 bool uncommitted) { 264 scoped_ptr<base::Value> observed_value_ptr(base::JSONReader::Read(json)); 265 const base::DictionaryValue* observed_dict; 266 ASSERT_TRUE(observed_value_ptr.get()); 267 ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict)); 268 VerifyPref(observed_dict, name, value, controlledBy, disabled, uncommitted); 269 } 270 271 void PreferencesBrowserTest::VerifyObservedPrefs( 272 const std::string& json, 273 const std::vector<std::string>& names, 274 const std::vector<base::Value*>& values, 275 const std::string& controlledBy, 276 bool disabled, 277 bool uncommitted) { 278 scoped_ptr<base::Value> observed_value_ptr(base::JSONReader::Read(json)); 279 const base::DictionaryValue* observed_dict; 280 ASSERT_TRUE(observed_value_ptr.get()); 281 ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict)); 282 for (size_t i = 0; i < names.size(); ++i) { 283 VerifyPref(observed_dict, names[i], values[i], controlledBy, disabled, 284 uncommitted); 285 } 286 } 287 288 void PreferencesBrowserTest::ExpectNoCommit(const std::string& name) { 289 pref_change_registrar_.Add( 290 name.c_str(), 291 base::Bind(&PreferencesBrowserTest::OnPreferenceChanged, 292 base::Unretained(this))); 293 EXPECT_CALL(*this, OnCommit(Property(&PrefService::Preference::name, name))) 294 .Times(0); 295 } 296 297 void PreferencesBrowserTest::ExpectSetCommit(const std::string& name, 298 const base::Value* value) { 299 pref_change_registrar_.Add( 300 name.c_str(), 301 base::Bind(&PreferencesBrowserTest::OnPreferenceChanged, 302 base::Unretained(this))); 303 EXPECT_CALL(*this, OnCommit(AllOf( 304 Property(&PrefService::Preference::name, name), 305 Property(&PrefService::Preference::IsUserControlled, true), 306 Property(&PrefService::Preference::GetValue, EqualsValue(value))))); 307 } 308 309 void PreferencesBrowserTest::ExpectClearCommit(const std::string& name) { 310 pref_change_registrar_.Add( 311 name.c_str(), 312 base::Bind(&PreferencesBrowserTest::OnPreferenceChanged, 313 base::Unretained(this))); 314 EXPECT_CALL(*this, OnCommit(AllOf( 315 Property(&PrefService::Preference::name, name), 316 Property(&PrefService::Preference::IsUserControlled, false)))); 317 } 318 319 void PreferencesBrowserTest::VerifyAndClearExpectations() { 320 Mock::VerifyAndClearExpectations(this); 321 pref_change_registrar_.RemoveAll(); 322 } 323 324 void PreferencesBrowserTest::SetupJavaScriptTestEnvironment( 325 const std::vector<std::string>& pref_names, 326 std::string* observed_json) const { 327 std::stringstream javascript; 328 javascript << "var testEnv = new TestEnv();"; 329 for (std::vector<std::string>::const_iterator name = pref_names.begin(); 330 name != pref_names.end(); ++name) { 331 javascript << "testEnv.addPref('" << name->c_str() << "');"; 332 } 333 javascript << "testEnv.setupAndReply();"; 334 std::string temp_observed_json; 335 if (!observed_json) 336 observed_json = &temp_observed_json; 337 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 338 render_view_host_, javascript.str(), observed_json)); 339 } 340 341 void PreferencesBrowserTest::SetPref(const std::string& name, 342 const std::string& type, 343 const base::Value* value, 344 bool commit, 345 std::string* observed_json) { 346 scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit)); 347 std::stringstream javascript; 348 javascript << "testEnv.runAndReply(function() {" 349 << " Preferences.set" << type << "Pref(" 350 << " '" << name << "'," 351 << " " << *value << "," 352 << " " << *commit_ptr << ");" 353 << "});"; 354 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 355 render_view_host_, javascript.str(), observed_json)); 356 } 357 358 void PreferencesBrowserTest::VerifySetPref(const std::string& name, 359 const std::string& type, 360 const base::Value* value, 361 bool commit) { 362 if (commit) 363 ExpectSetCommit(name, value); 364 else 365 ExpectNoCommit(name); 366 std::string observed_json; 367 SetPref(name, type, value, commit, &observed_json); 368 VerifyObservedPref(observed_json, name, value, std::string(), false, !commit); 369 VerifyAndClearExpectations(); 370 } 371 372 void PreferencesBrowserTest::VerifyClearPref(const std::string& name, 373 const base::Value* value, 374 bool commit) { 375 if (commit) 376 ExpectClearCommit(name); 377 else 378 ExpectNoCommit(name); 379 scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit)); 380 std::string commit_json; 381 base::JSONWriter::Write(commit_ptr.get(), &commit_json); 382 std::stringstream javascript; 383 javascript << "testEnv.runAndReply(function() {" 384 << " Preferences.clearPref(" 385 << " '" << name.c_str() << "'," 386 << " " << commit_json.c_str() << ");});"; 387 std::string observed_json; 388 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 389 render_view_host_, javascript.str(), &observed_json)); 390 VerifyObservedPref(observed_json, name, value, "recommended", false, !commit); 391 VerifyAndClearExpectations(); 392 } 393 394 void PreferencesBrowserTest::VerifyCommit(const std::string& name, 395 const base::Value* value, 396 const std::string& controlledBy) { 397 std::stringstream javascript; 398 javascript << "testEnv.runAndReply(function() {" 399 << " Preferences.getInstance().commitPref(" 400 << " '" << name.c_str() << "');});"; 401 std::string observed_json; 402 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 403 render_view_host_, javascript.str(), &observed_json)); 404 VerifyObservedPref(observed_json, name, value, controlledBy, false, false); 405 } 406 407 void PreferencesBrowserTest::VerifySetCommit(const std::string& name, 408 const base::Value* value) { 409 ExpectSetCommit(name, value); 410 VerifyCommit(name, value, std::string()); 411 VerifyAndClearExpectations(); 412 } 413 414 void PreferencesBrowserTest::VerifyClearCommit(const std::string& name, 415 const base::Value* value) { 416 ExpectClearCommit(name); 417 VerifyCommit(name, value, "recommended"); 418 VerifyAndClearExpectations(); 419 } 420 421 void PreferencesBrowserTest::VerifyRollback(const std::string& name, 422 const base::Value* value, 423 const std::string& controlledBy) { 424 ExpectNoCommit(name); 425 std::stringstream javascript; 426 javascript << "testEnv.runAndReply(function() {" 427 << " Preferences.getInstance().rollbackPref(" 428 << " '" << name.c_str() << "');});"; 429 std::string observed_json; 430 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 431 render_view_host_, javascript.str(), &observed_json)); 432 VerifyObservedPref(observed_json, name, value, controlledBy, false, true); 433 VerifyAndClearExpectations(); 434 } 435 436 void PreferencesBrowserTest::StartObserving() { 437 ASSERT_TRUE(content::ExecuteScript( 438 render_view_host_, "testEnv.startObserving();")); 439 } 440 441 void PreferencesBrowserTest::FinishObserving(std::string* observed_json) { 442 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 443 render_view_host_, 444 "testEnv.finishObservingAndReply();", 445 observed_json)); 446 } 447 448 void PreferencesBrowserTest::UseDefaultTestPrefs(bool includeListPref) { 449 // Boolean pref. 450 types_.push_back("Boolean"); 451 pref_names_.push_back(prefs::kAlternateErrorPagesEnabled); 452 policy_names_.push_back(policy::key::kAlternateErrorPagesEnabled); 453 non_default_values_.push_back(new base::FundamentalValue(false)); 454 455 // Integer pref. 456 types_.push_back("Integer"); 457 pref_names_.push_back(prefs::kRestoreOnStartup); 458 policy_names_.push_back(policy::key::kRestoreOnStartup); 459 non_default_values_.push_back(new base::FundamentalValue(4)); 460 461 // List pref. 462 if (includeListPref) { 463 types_.push_back("List"); 464 pref_names_.push_back(prefs::kURLsToRestoreOnStartup); 465 policy_names_.push_back(policy::key::kRestoreOnStartupURLs); 466 base::ListValue* list = new base::ListValue; 467 list->Append(new base::StringValue("http://www.example.com")); 468 list->Append(new base::StringValue("http://example.com")); 469 non_default_values_.push_back(list); 470 } 471 472 // Retrieve default values. 473 for (std::vector<std::string>::const_iterator name = pref_names_.begin(); 474 name != pref_names_.end(); ++name) { 475 default_values_.push_back( 476 pref_service_->GetDefaultPrefValue(name->c_str())->DeepCopy()); 477 } 478 } 479 480 // Verifies that initializing the JavaScript Preferences class fires the correct 481 // notifications in JavaScript. 482 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, FetchPrefs) { 483 UseDefaultTestPrefs(true); 484 std::string observed_json; 485 486 // Verify notifications when default values are in effect. 487 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 488 VerifyObservedPrefs( 489 observed_json, pref_names_, default_values_.get(), 490 std::string(), false, false); 491 492 // Verify notifications when recommended values are in effect. 493 SetUserPolicies(policy_names_, non_default_values_.get(), 494 policy::POLICY_LEVEL_RECOMMENDED); 495 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 496 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(), 497 "recommended", false, false); 498 499 // Verify notifications when mandatory values are in effect. 500 SetUserPolicies(policy_names_, non_default_values_.get(), 501 policy::POLICY_LEVEL_MANDATORY); 502 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 503 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(), 504 "policy", true, false); 505 506 // Verify notifications when user-modified values are in effect. 507 ClearUserPolicies(); 508 SetUserValues(pref_names_, non_default_values_.get()); 509 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 510 VerifyObservedPrefs(observed_json, 511 pref_names_, 512 non_default_values_.get(), 513 std::string(), 514 false, 515 false); 516 } 517 518 // Verifies that setting a user-modified pref value through the JavaScript 519 // Preferences class fires the correct notification in JavaScript and causes the 520 // change to be committed to the C++ backend. 521 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, SetPrefs) { 522 UseDefaultTestPrefs(false); 523 524 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 525 for (size_t i = 0; i < pref_names_.size(); ++i) { 526 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], true); 527 } 528 } 529 530 // Verifies that clearing a user-modified pref value through the JavaScript 531 // Preferences class fires the correct notification in JavaScript and causes the 532 // change to be committed to the C++ backend. 533 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ClearPrefs) { 534 UseDefaultTestPrefs(false); 535 536 SetUserPolicies(policy_names_, default_values_.get(), 537 policy::POLICY_LEVEL_RECOMMENDED); 538 SetUserValues(pref_names_, non_default_values_.get()); 539 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 540 for (size_t i = 0; i < pref_names_.size(); ++i) { 541 VerifyClearPref(pref_names_[i], default_values_[i], true); 542 } 543 } 544 545 // Verifies that when the user-modified value of a dialog pref is set and the 546 // change then committed through the JavaScript Preferences class, the correct 547 // notifications fire and a commit to the C++ backend occurs in the latter step 548 // only. 549 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetCommit) { 550 UseDefaultTestPrefs(false); 551 552 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 553 for (size_t i = 0; i < pref_names_.size(); ++i) { 554 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false); 555 VerifySetCommit(pref_names_[i], non_default_values_[i]); 556 } 557 } 558 559 // Verifies that when the user-modified value of a dialog pref is set and the 560 // change then rolled back through the JavaScript Preferences class, the correct 561 // notifications fire and no commit to the C++ backend occurs. 562 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetRollback) { 563 UseDefaultTestPrefs(false); 564 565 // Verify behavior when default values are in effect. 566 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 567 for (size_t i = 0; i < pref_names_.size(); ++i) { 568 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false); 569 VerifyRollback(pref_names_[i], default_values_[i], std::string()); 570 } 571 572 // Verify behavior when recommended values are in effect. 573 SetUserPolicies(policy_names_, default_values_.get(), 574 policy::POLICY_LEVEL_RECOMMENDED); 575 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 576 for (size_t i = 0; i < pref_names_.size(); ++i) { 577 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false); 578 VerifyRollback(pref_names_[i], default_values_[i], "recommended"); 579 } 580 } 581 582 // Verifies that when the user-modified value of a dialog pref is cleared and 583 // the change then committed through the JavaScript Preferences class, the 584 // correct notifications fire and a commit to the C++ backend occurs in the 585 // latter step only. 586 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearCommit) { 587 UseDefaultTestPrefs(false); 588 589 SetUserPolicies(policy_names_, default_values_.get(), 590 policy::POLICY_LEVEL_RECOMMENDED); 591 SetUserValues(pref_names_, non_default_values_.get()); 592 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 593 for (size_t i = 0; i < pref_names_.size(); ++i) { 594 VerifyClearPref(pref_names_[i], default_values_[i], false); 595 VerifyClearCommit(pref_names_[i], default_values_[i]); 596 } 597 } 598 599 // Verifies that when the user-modified value of a dialog pref is cleared and 600 // the change then rolled back through the JavaScript Preferences class, the 601 // correct notifications fire and no commit to the C++ backend occurs. 602 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearRollback) { 603 UseDefaultTestPrefs(false); 604 605 SetUserPolicies(policy_names_, default_values_.get(), 606 policy::POLICY_LEVEL_RECOMMENDED); 607 SetUserValues(pref_names_, non_default_values_.get()); 608 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 609 for (size_t i = 0; i < pref_names_.size(); ++i) { 610 VerifyClearPref(pref_names_[i], default_values_[i], false); 611 VerifyRollback(pref_names_[i], non_default_values_[i], std::string()); 612 } 613 } 614 615 // Verifies that when preference values change in the C++ backend, the correct 616 // notifications fire in JavaScript. 617 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, NotificationsOnBackendChanges) { 618 UseDefaultTestPrefs(false); 619 std::string observed_json; 620 621 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 622 623 // Verify notifications when recommended values come into effect. 624 StartObserving(); 625 SetUserPolicies(policy_names_, non_default_values_.get(), 626 policy::POLICY_LEVEL_RECOMMENDED); 627 FinishObserving(&observed_json); 628 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(), 629 "recommended", false, false); 630 631 // Verify notifications when mandatory values come into effect. 632 StartObserving(); 633 SetUserPolicies(policy_names_, non_default_values_.get(), 634 policy::POLICY_LEVEL_MANDATORY); 635 FinishObserving(&observed_json); 636 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(), 637 "policy", true, false); 638 639 // Verify notifications when default values come into effect. 640 StartObserving(); 641 ClearUserPolicies(); 642 FinishObserving(&observed_json); 643 VerifyObservedPrefs( 644 observed_json, pref_names_, default_values_.get(), 645 std::string(), false, false); 646 647 // Verify notifications when user-modified values come into effect. 648 StartObserving(); 649 SetUserValues(pref_names_, non_default_values_.get()); 650 FinishObserving(&observed_json); 651 VerifyObservedPrefs(observed_json, 652 pref_names_, 653 non_default_values_.get(), 654 std::string(), 655 false, 656 false); 657 } 658 659 #if defined(OS_CHROMEOS) 660 661 // Verifies that initializing the JavaScript Preferences class fires the correct 662 // notifications in JavaScript for pref values handled by the 663 // CoreChromeOSOptionsHandler class. 664 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ChromeOSDeviceFetchPrefs) { 665 std::string observed_json; 666 667 // Boolean pref. 668 pref_names_.push_back(chromeos::kAccountsPrefAllowGuest); 669 default_values_.push_back(new base::FundamentalValue(true)); 670 671 // String pref. 672 pref_names_.push_back(chromeos::kReleaseChannel); 673 default_values_.push_back(new base::StringValue("")); 674 675 // List pref. 676 pref_names_.push_back(chromeos::kAccountsPrefUsers); 677 default_values_.push_back(new base::ListValue); 678 679 // Verify notifications when default values are in effect. 680 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 681 VerifyObservedPrefs(observed_json, pref_names_, default_values_.get(), 682 "owner", true, false); 683 } 684 685 // Verifies that initializing the JavaScript Preferences class fires the correct 686 // notifications in JavaScript for non-privileged pref values handled by the 687 // CoreChromeOSOptionsHandler class. 688 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, 689 ChromeOSDeviceFetchNonPrivilegedPrefs) { 690 ScopedVector<base::Value> decorated_non_default_values; 691 std::string observed_json; 692 693 // Non-privileged string pref. 694 pref_names_.push_back(chromeos::kSystemTimezone); 695 default_values_.push_back(new base::StringValue("America/Los_Angeles")); 696 non_default_values_.push_back(new base::StringValue("America/New_York")); 697 decorated_non_default_values.push_back( 698 non_default_values_.back()->DeepCopy()); 699 700 // Verify notifications when default values are in effect. 701 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 702 VerifyObservedPrefs(observed_json, pref_names_, default_values_.get(), 703 std::string(), false, false); 704 705 chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); 706 cros_settings->Set(pref_names_[0], *non_default_values_[0]); 707 708 // Verify notifications when non-default values are in effect. 709 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 710 VerifyObservedPrefs(observed_json, pref_names_, 711 decorated_non_default_values.get(), 712 std::string(), false, false); 713 } 714 715 class ManagedPreferencesBrowserTest : public PreferencesBrowserTest { 716 protected: 717 // PreferencesBrowserTest implementation: 718 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 719 // Set up fake install attributes. 720 scoped_ptr<policy::StubEnterpriseInstallAttributes> attributes( 721 new policy::StubEnterpriseInstallAttributes()); 722 attributes->SetDomain("example.com"); 723 attributes->SetRegistrationUser("user (at) example.com"); 724 policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting( 725 attributes.release()); 726 727 PreferencesBrowserTest::SetUpInProcessBrowserTestFixture(); 728 } 729 }; 730 731 // Verifies that initializing the JavaScript Preferences class fires the correct 732 // notifications in JavaScript for pref values handled by the 733 // CoreChromeOSOptionsHandler class for a managed device. 734 IN_PROC_BROWSER_TEST_F(ManagedPreferencesBrowserTest, 735 ChromeOSDeviceFetchPrefs) { 736 ScopedVector<base::Value> decorated_non_default_values; 737 std::string observed_json; 738 739 // Boolean pref. 740 pref_names_.push_back(chromeos::kAccountsPrefAllowGuest); 741 non_default_values_.push_back(new base::FundamentalValue(false)); 742 decorated_non_default_values.push_back( 743 non_default_values_.back()->DeepCopy()); 744 745 // String pref. 746 pref_names_.push_back(chromeos::kReleaseChannel); 747 non_default_values_.push_back(new base::StringValue("stable-channel")); 748 decorated_non_default_values.push_back( 749 non_default_values_.back()->DeepCopy()); 750 751 // List pref. 752 pref_names_.push_back(chromeos::kAccountsPrefUsers); 753 base::ListValue* list = new base::ListValue; 754 list->Append(new base::StringValue("me (at) google.com")); 755 list->Append(new base::StringValue("you (at) google.com")); 756 non_default_values_.push_back(list); 757 list = new base::ListValue; 758 base::DictionaryValue* dict = new base::DictionaryValue; 759 dict->SetString("username", "me (at) google.com"); 760 dict->SetString("name", "me (at) google.com"); 761 dict->SetString("email", ""); 762 dict->SetBoolean("owner", false); 763 list->Append(dict); 764 dict = new base::DictionaryValue; 765 dict->SetString("username", "you (at) google.com"); 766 dict->SetString("name", "you (at) google.com"); 767 dict->SetString("email", ""); 768 dict->SetBoolean("owner", false); 769 list->Append(dict); 770 decorated_non_default_values.push_back(list); 771 772 chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); 773 for (size_t i = 0; i < pref_names_.size(); ++i) { 774 cros_settings->Set(pref_names_[i], *non_default_values_[i]); 775 } 776 777 // Verify notifications when mandatory values are in effect. 778 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 779 VerifyObservedPrefs(observed_json, pref_names_, 780 decorated_non_default_values.get(), 781 "policy", true, false); 782 } 783 784 // Verifies that initializing the JavaScript Preferences class fires the correct 785 // notifications in JavaScript for non-privileged pref values handled by the 786 // CoreChromeOSOptionsHandler class for a managed device. 787 IN_PROC_BROWSER_TEST_F(ManagedPreferencesBrowserTest, 788 ChromeOSDeviceFetchNonPrivilegedPrefs) { 789 ScopedVector<base::Value> decorated_non_default_values; 790 std::string observed_json; 791 792 // Non-privileged string pref. 793 pref_names_.push_back(chromeos::kSystemTimezone); 794 non_default_values_.push_back(new base::StringValue("America/New_York")); 795 decorated_non_default_values.push_back( 796 non_default_values_.back()->DeepCopy()); 797 798 // Verify notifications when mandatory values are in effect. 799 chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); 800 cros_settings->Set(pref_names_[0], *non_default_values_[0]); 801 802 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 803 VerifyObservedPrefs(observed_json, pref_names_, 804 decorated_non_default_values.get(), 805 std::string(), false, false); 806 } 807 808 namespace { 809 810 const char* kUserProfilePath = "user_profile"; 811 812 } // namespace 813 814 class ProxyPreferencesBrowserTest : public PreferencesBrowserTest { 815 public: 816 virtual void SetUpOnMainThread() OVERRIDE { 817 SetupNetworkEnvironment(); 818 content::RunAllPendingInMessageLoop(); 819 820 scoped_ptr<base::DictionaryValue> proxy_config_dict( 821 ProxyConfigDictionary::CreateFixedServers("127.0.0.1:8080", 822 "*.google.com, 1.2.3.4:22")); 823 824 ProxyConfigDictionary proxy_config(proxy_config_dict.get()); 825 826 const chromeos::NetworkState* network = GetDefaultNetwork(); 827 ASSERT_TRUE(network); 828 chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config, *network); 829 830 std::string url = base::StringPrintf("%s?network=%s", 831 chrome::kChromeUIProxySettingsURL, 832 network->path().c_str()); 833 834 ui_test_utils::NavigateToURL(browser(), GURL(url)); 835 SetUpPrefs(); 836 } 837 838 protected: 839 void SetupNetworkEnvironment() { 840 chromeos::ShillProfileClient::TestInterface* profile_test = 841 chromeos::DBusThreadManager::Get()->GetShillProfileClient() 842 ->GetTestInterface(); 843 chromeos::ShillServiceClient::TestInterface* service_test = 844 chromeos::DBusThreadManager::Get()->GetShillServiceClient() 845 ->GetTestInterface(); 846 847 profile_test->AddProfile(kUserProfilePath, "user"); 848 849 service_test->ClearServices(); 850 service_test->AddService("stub_ethernet", 851 "eth0", 852 shill::kTypeEthernet, 853 shill::kStateOnline, 854 true /* add_to_visible */ ); 855 service_test->SetServiceProperty("stub_ethernet", 856 shill::kGuidProperty, 857 base::StringValue("stub_ethernet")); 858 service_test->SetServiceProperty("stub_ethernet", 859 shill::kProfileProperty, 860 base::StringValue(kUserProfilePath)); 861 profile_test->AddService(kUserProfilePath, "stub_wifi2"); 862 } 863 864 void SetONCPolicy(const char* policy_name, policy::PolicyScope scope) { 865 std::string onc_policy = 866 "{ \"NetworkConfigurations\": [" 867 " { \"GUID\": \"stub_ethernet\"," 868 " \"Type\": \"Ethernet\"," 869 " \"Name\": \"My Ethernet\"," 870 " \"Ethernet\": {" 871 " \"Authentication\": \"None\" }," 872 " \"ProxySettings\": {" 873 " \"PAC\": \"http://domain.com/x\"," 874 " \"Type\": \"PAC\" }" 875 " }" 876 " ]," 877 " \"Type\": \"UnencryptedConfiguration\"" 878 "}"; 879 880 policy::PolicyMap map; 881 map.Set(policy_name, 882 policy::POLICY_LEVEL_MANDATORY, 883 scope, 884 new base::StringValue(onc_policy), 885 NULL); 886 policy_provider_.UpdateChromePolicy(map); 887 888 content::RunAllPendingInMessageLoop(); 889 } 890 891 const chromeos::NetworkState* GetDefaultNetwork() { 892 chromeos::NetworkStateHandler* handler = 893 chromeos::NetworkHandler::Get()->network_state_handler(); 894 return handler->DefaultNetwork(); 895 } 896 897 void SetProxyPref(const std::string& name, const base::Value& value) { 898 std::string type; 899 switch (value.GetType()) { 900 case base::Value::TYPE_BOOLEAN: 901 type = "Boolean"; 902 break; 903 case base::Value::TYPE_INTEGER: 904 type = "Integer"; 905 break; 906 case base::Value::TYPE_STRING: 907 type = "String"; 908 break; 909 default: 910 ASSERT_TRUE(false); 911 } 912 913 std::string observed_json; 914 SetPref(name, type, &value, true, &observed_json); 915 } 916 917 void VerifyCurrentProxyServer(const std::string& expected_server, 918 onc::ONCSource expected_source) { 919 const chromeos::NetworkState* network = GetDefaultNetwork(); 920 ASSERT_TRUE(network); 921 onc::ONCSource actual_source; 922 scoped_ptr<ProxyConfigDictionary> proxy_dict = 923 chromeos::proxy_config::GetProxyConfigForNetwork( 924 pref_service_, 925 g_browser_process->local_state(), 926 *network, 927 &actual_source); 928 ASSERT_TRUE(proxy_dict); 929 std::string actual_proxy_server; 930 EXPECT_TRUE(proxy_dict->GetProxyServer(&actual_proxy_server)); 931 EXPECT_EQ(expected_server, actual_proxy_server); 932 EXPECT_EQ(expected_source, actual_source); 933 } 934 }; 935 936 // Verifies that proxy settings are correctly pushed to JavaScript during 937 // initialization of the proxy settings page. 938 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSInitializeProxy) { 939 // Boolean pref. 940 pref_names_.push_back(chromeos::kProxySingle); 941 non_default_values_.push_back(new base::FundamentalValue(true)); 942 943 // Integer prefs. 944 pref_names_.push_back(chromeos::kProxySingleHttpPort); 945 non_default_values_.push_back(new base::FundamentalValue(8080)); 946 947 // String pref. 948 pref_names_.push_back(chromeos::kProxySingleHttp); 949 non_default_values_.push_back(new base::StringValue("127.0.0.1")); 950 951 // List pref. 952 pref_names_.push_back(chromeos::kProxyIgnoreList); 953 base::ListValue* list = new base::ListValue(); 954 list->Append(new base::StringValue("*.google.com")); 955 list->Append(new base::StringValue("1.2.3.4:22")); 956 non_default_values_.push_back(list); 957 958 // Verify that no policy is presented to the UI. This must be verified on the 959 // kProxyType and the kUseSharedProxies prefs. 960 pref_names_.push_back(chromeos::kProxyType); 961 non_default_values_.push_back(new base::FundamentalValue(2)); 962 963 pref_names_.push_back(prefs::kUseSharedProxies); 964 non_default_values_.push_back(new base::FundamentalValue(false)); 965 966 std::string observed_json; 967 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 968 VerifyObservedPrefs( 969 observed_json, pref_names_, non_default_values_.get(), "", false, false); 970 } 971 972 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ONCPolicy) { 973 SetONCPolicy(policy::key::kOpenNetworkConfiguration, 974 policy::POLICY_SCOPE_USER); 975 976 // Verify that per-network policy is presented to the UI. This must be 977 // verified on the kProxyType. 978 pref_names_.push_back(chromeos::kProxyType); 979 non_default_values_.push_back(new base::FundamentalValue(3)); 980 981 std::string observed_json; 982 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 983 VerifyObservedPrefs( 984 observed_json, pref_names_, non_default_values_.get(), 985 "policy", true, false); 986 987 // Verify that 'use-shared-proxies' is not affected by per-network policy. 988 pref_names_.clear(); 989 non_default_values_.clear(); 990 pref_names_.push_back(prefs::kUseSharedProxies); 991 non_default_values_.push_back(new base::FundamentalValue(false)); 992 993 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 994 VerifyObservedPrefs( 995 observed_json, pref_names_, non_default_values_.get(), "", false, false); 996 } 997 998 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, DeviceONCPolicy) { 999 SetONCPolicy(policy::key::kDeviceOpenNetworkConfiguration, 1000 policy::POLICY_SCOPE_MACHINE); 1001 1002 // Verify that the policy is presented to the UI. This verification must be 1003 // done on the kProxyType pref. 1004 pref_names_.push_back(chromeos::kProxyType); 1005 non_default_values_.push_back(new base::FundamentalValue(3)); 1006 1007 std::string observed_json; 1008 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 1009 VerifyObservedPrefs( 1010 observed_json, pref_names_, non_default_values_.get(), 1011 "policy", true, false); 1012 1013 // Verify that 'use-shared-proxies' is not affected by per-network policy. 1014 pref_names_.clear(); 1015 non_default_values_.clear(); 1016 pref_names_.push_back(prefs::kUseSharedProxies); 1017 non_default_values_.push_back(new base::FundamentalValue(false)); 1018 1019 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 1020 VerifyObservedPrefs( 1021 observed_json, pref_names_, non_default_values_.get(), "", false, false); 1022 } 1023 1024 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, UserProxyPolicy) { 1025 policy_names_.push_back(policy::key::kProxyMode); 1026 default_values_.push_back( 1027 new base::StringValue(ProxyPrefs::kAutoDetectProxyModeName)); 1028 SetUserPolicies( 1029 policy_names_, default_values_.get(), policy::POLICY_LEVEL_MANDATORY); 1030 content::RunAllPendingInMessageLoop(); 1031 1032 // Verify that the policy is presented to the UI. This verification must be 1033 // done on the kProxyType pref. 1034 pref_names_.push_back(chromeos::kProxyType); 1035 non_default_values_.push_back(new base::FundamentalValue(3)); 1036 1037 // Verify that 'use-shared-proxies' is controlled by the policy. 1038 pref_names_.push_back(prefs::kUseSharedProxies); 1039 non_default_values_.push_back(new base::FundamentalValue(false)); 1040 1041 std::string observed_json; 1042 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 1043 VerifyObservedPrefs( 1044 observed_json, pref_names_, non_default_values_.get(), 1045 "policy", true, false); 1046 } 1047 1048 // Verifies that modifications to the proxy settings are correctly pushed from 1049 // JavaScript to the ProxyConfig property stored in the network configuration. 1050 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSSetProxy) { 1051 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 1052 1053 SetProxyPref(chromeos::kProxySingleHttpPort, base::FundamentalValue(123)); 1054 SetProxyPref(chromeos::kProxySingleHttp, base::StringValue("www.adomain.xy")); 1055 1056 VerifyCurrentProxyServer("www.adomain.xy:123", 1057 onc::ONC_SOURCE_NONE); 1058 } 1059 1060 // Verify that default proxy ports are used and that ports can be updated 1061 // without affecting the previously set hosts. 1062 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSProxyDefaultPorts) { 1063 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 1064 1065 // Set to manual, per scheme proxy. 1066 SetProxyPref(chromeos::kProxySingle, base::FundamentalValue(false)); 1067 1068 // Set hosts but no ports. 1069 SetProxyPref(chromeos::kProxyHttpUrl, base::StringValue("a.com")); 1070 SetProxyPref(chromeos::kProxyHttpsUrl, base::StringValue("4.3.2.1")); 1071 SetProxyPref(chromeos::kProxyFtpUrl, base::StringValue("c.com")); 1072 SetProxyPref(chromeos::kProxySocks, base::StringValue("d.com")); 1073 1074 // Verify default ports. 1075 VerifyCurrentProxyServer( 1076 "http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080", 1077 onc::ONC_SOURCE_NONE); 1078 1079 // Set and verify the ports. 1080 SetProxyPref(chromeos::kProxyHttpPort, base::FundamentalValue(1)); 1081 SetProxyPref(chromeos::kProxyHttpsPort, base::FundamentalValue(2)); 1082 SetProxyPref(chromeos::kProxyFtpPort, base::FundamentalValue(3)); 1083 SetProxyPref(chromeos::kProxySocksPort, base::FundamentalValue(4)); 1084 1085 VerifyCurrentProxyServer( 1086 "http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4", 1087 onc::ONC_SOURCE_NONE); 1088 } 1089 1090 #endif 1091