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/stl_util.h" 16 #include "base/values.h" 17 #include "chrome/browser/chrome_notification_types.h" 18 #include "chrome/browser/policy/browser_policy_connector.h" 19 #include "chrome/browser/policy/external_data_fetcher.h" 20 #include "chrome/browser/policy/policy_map.h" 21 #include "chrome/browser/policy/policy_types.h" 22 #include "chrome/browser/profiles/profile.h" 23 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/tabs/tab_strip_model.h" 25 #include "chrome/common/pref_names.h" 26 #include "chrome/common/url_constants.h" 27 #include "chrome/test/base/ui_test_utils.h" 28 #include "content/public/browser/notification_details.h" 29 #include "content/public/browser/notification_source.h" 30 #include "content/public/browser/render_view_host.h" 31 #include "content/public/browser/web_contents.h" 32 #include "content/public/test/browser_test_utils.h" 33 #include "policy/policy_constants.h" 34 #include "testing/gtest/include/gtest/gtest.h" 35 #include "url/gurl.h" 36 37 #if defined(OS_CHROMEOS) 38 #include "base/strings/stringprintf.h" 39 #include "chrome/browser/browser_process.h" 40 #include "chrome/browser/chromeos/net/proxy_config_handler.h" 41 #include "chrome/browser/chromeos/proxy_cros_settings_parser.h" 42 #include "chrome/browser/chromeos/settings/cros_settings.h" 43 #include "chrome/browser/chromeos/settings/cros_settings_names.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 "content/public/test/test_utils.h" 51 #include "third_party/cros_system_api/dbus/service_constants.h" 52 #endif 53 54 using testing::AllOf; 55 using testing::AnyNumber; 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 Value& first, const 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 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 EXPECT_CALL(policy_provider_, RegisterPolicyDomain(_)) 194 .Times(AnyNumber()); 195 policy::BrowserPolicyConnector::SetPolicyProviderForTesting( 196 &policy_provider_); 197 }; 198 199 void PreferencesBrowserTest::TearDownInProcessBrowserTestFixture() { 200 STLDeleteElements(&default_values_); 201 STLDeleteElements(&non_default_values_); 202 } 203 204 void PreferencesBrowserTest::SetUserPolicies( 205 const std::vector<std::string>& names, 206 const std::vector<base::Value*>& values, 207 policy::PolicyLevel level) { 208 policy::PolicyMap map; 209 for (size_t i = 0; i < names.size(); ++i) { 210 map.Set(names[i], level, policy::POLICY_SCOPE_USER, 211 values[i]->DeepCopy(), NULL); 212 } 213 policy_provider_.UpdateChromePolicy(map); 214 } 215 216 void PreferencesBrowserTest::ClearUserPolicies() { 217 policy::PolicyMap empty_policy_map; 218 policy_provider_.UpdateChromePolicy(empty_policy_map); 219 } 220 221 void PreferencesBrowserTest::SetUserValues( 222 const std::vector<std::string>& names, 223 const std::vector<base::Value*>& values) { 224 for (size_t i = 0; i < names.size(); ++i) 225 pref_service_->Set(names[i].c_str(), *values[i]); 226 } 227 228 void PreferencesBrowserTest::VerifyKeyValue(const base::DictionaryValue& dict, 229 const std::string& key, 230 const base::Value& expected) { 231 const base::Value* actual = NULL; 232 EXPECT_TRUE(dict.Get(key, &actual)) << "Was checking key: " << key; 233 EXPECT_EQ(expected, *actual) << "Was checking key: " << key; 234 } 235 236 void PreferencesBrowserTest::VerifyPref(const base::DictionaryValue* prefs, 237 const std::string& name, 238 const base::Value* value, 239 const std::string& controlledBy, 240 bool disabled, 241 bool uncommitted) { 242 const base::Value* pref; 243 const base::DictionaryValue* dict; 244 ASSERT_TRUE(prefs->GetWithoutPathExpansion(name, &pref)); 245 ASSERT_TRUE(pref->GetAsDictionary(&dict)); 246 VerifyKeyValue(*dict, "value", *value); 247 if (!controlledBy.empty()) { 248 VerifyKeyValue(*dict, "controlledBy", base::StringValue(controlledBy)); 249 } else { 250 EXPECT_FALSE(dict->HasKey("controlledBy")); 251 } 252 if (disabled) 253 VerifyKeyValue(*dict, "disabled", base::FundamentalValue(true)); 254 else if (dict->HasKey("disabled")) 255 VerifyKeyValue(*dict, "disabled", base::FundamentalValue(false)); 256 if (uncommitted) 257 VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(true)); 258 else if (dict->HasKey("uncommitted")) 259 VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(false)); 260 } 261 262 void PreferencesBrowserTest::VerifyObservedPref(const std::string& json, 263 const std::string& name, 264 const base::Value* value, 265 const std::string& controlledBy, 266 bool disabled, 267 bool uncommitted) { 268 scoped_ptr<base::Value> observed_value_ptr(base::JSONReader::Read(json)); 269 const base::DictionaryValue* observed_dict; 270 ASSERT_TRUE(observed_value_ptr.get()); 271 ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict)); 272 VerifyPref(observed_dict, name, value, controlledBy, disabled, uncommitted); 273 } 274 275 void PreferencesBrowserTest::VerifyObservedPrefs( 276 const std::string& json, 277 const std::vector<std::string>& names, 278 const std::vector<base::Value*>& values, 279 const std::string& controlledBy, 280 bool disabled, 281 bool uncommitted) { 282 scoped_ptr<base::Value> observed_value_ptr(base::JSONReader::Read(json)); 283 const base::DictionaryValue* observed_dict; 284 ASSERT_TRUE(observed_value_ptr.get()); 285 ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict)); 286 for (size_t i = 0; i < names.size(); ++i) 287 VerifyPref(observed_dict, names[i], values[i], controlledBy, disabled, 288 uncommitted); 289 } 290 291 void PreferencesBrowserTest::ExpectNoCommit(const std::string& name) { 292 pref_change_registrar_.Add( 293 name.c_str(), 294 base::Bind(&PreferencesBrowserTest::OnPreferenceChanged, 295 base::Unretained(this))); 296 EXPECT_CALL(*this, OnCommit(Property(&PrefService::Preference::name, name))) 297 .Times(0); 298 } 299 300 void PreferencesBrowserTest::ExpectSetCommit(const std::string& name, 301 const base::Value* value) { 302 pref_change_registrar_.Add( 303 name.c_str(), 304 base::Bind(&PreferencesBrowserTest::OnPreferenceChanged, 305 base::Unretained(this))); 306 EXPECT_CALL(*this, OnCommit(AllOf( 307 Property(&PrefService::Preference::name, name), 308 Property(&PrefService::Preference::IsUserControlled, true), 309 Property(&PrefService::Preference::GetValue, EqualsValue(value))))); 310 } 311 312 void PreferencesBrowserTest::ExpectClearCommit(const std::string& name) { 313 pref_change_registrar_.Add( 314 name.c_str(), 315 base::Bind(&PreferencesBrowserTest::OnPreferenceChanged, 316 base::Unretained(this))); 317 EXPECT_CALL(*this, OnCommit(AllOf( 318 Property(&PrefService::Preference::name, name), 319 Property(&PrefService::Preference::IsUserControlled, false)))); 320 } 321 322 void PreferencesBrowserTest::VerifyAndClearExpectations() { 323 Mock::VerifyAndClearExpectations(this); 324 pref_change_registrar_.RemoveAll(); 325 } 326 327 void PreferencesBrowserTest::SetupJavaScriptTestEnvironment( 328 const std::vector<std::string>& pref_names, 329 std::string* observed_json) const { 330 std::stringstream javascript; 331 javascript << "var testEnv = new TestEnv();"; 332 for (std::vector<std::string>::const_iterator name = pref_names.begin(); 333 name != pref_names.end(); ++name) 334 javascript << "testEnv.addPref('" << name->c_str() << "');"; 335 javascript << "testEnv.setupAndReply();"; 336 std::string temp_observed_json; 337 if (!observed_json) 338 observed_json = &temp_observed_json; 339 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 340 render_view_host_, javascript.str(), observed_json)); 341 } 342 343 void PreferencesBrowserTest::SetPref(const std::string& name, 344 const std::string& type, 345 const base::Value* value, 346 bool commit, 347 std::string* observed_json) { 348 scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit)); 349 std::stringstream javascript; 350 javascript << "testEnv.runAndReply(function() {" 351 << " Preferences.set" << type << "Pref(" 352 << " '" << name << "'," 353 << " " << *value << "," 354 << " " << *commit_ptr << ");" 355 << "});"; 356 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 357 render_view_host_, javascript.str(), observed_json)); 358 } 359 360 void PreferencesBrowserTest::VerifySetPref(const std::string& name, 361 const std::string& type, 362 const base::Value* value, 363 bool commit) { 364 if (commit) 365 ExpectSetCommit(name, value); 366 else 367 ExpectNoCommit(name); 368 std::string observed_json; 369 SetPref(name, type, value, commit, &observed_json); 370 VerifyObservedPref(observed_json, name, value, std::string(), false, !commit); 371 VerifyAndClearExpectations(); 372 } 373 374 void PreferencesBrowserTest::VerifyClearPref(const std::string& name, 375 const base::Value* value, 376 bool commit) { 377 if (commit) 378 ExpectClearCommit(name); 379 else 380 ExpectNoCommit(name); 381 scoped_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit)); 382 std::string commit_json; 383 base::JSONWriter::Write(commit_ptr.get(), &commit_json); 384 std::stringstream javascript; 385 javascript << "testEnv.runAndReply(function() {" 386 << " Preferences.clearPref(" 387 << " '" << name.c_str() << "'," 388 << " " << commit_json.c_str() << ");});"; 389 std::string observed_json; 390 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 391 render_view_host_, javascript.str(), &observed_json)); 392 VerifyObservedPref(observed_json, name, value, "recommended", false, !commit); 393 VerifyAndClearExpectations(); 394 } 395 396 void PreferencesBrowserTest::VerifyCommit(const std::string& name, 397 const base::Value* value, 398 const std::string& controlledBy) { 399 std::stringstream javascript; 400 javascript << "testEnv.runAndReply(function() {" 401 << " Preferences.getInstance().commitPref(" 402 << " '" << name.c_str() << "');});"; 403 std::string observed_json; 404 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 405 render_view_host_, javascript.str(), &observed_json)); 406 VerifyObservedPref(observed_json, name, value, controlledBy, false, false); 407 } 408 409 void PreferencesBrowserTest::VerifySetCommit(const std::string& name, 410 const base::Value* value) { 411 ExpectSetCommit(name, value); 412 VerifyCommit(name, value, std::string()); 413 VerifyAndClearExpectations(); 414 } 415 416 void PreferencesBrowserTest::VerifyClearCommit(const std::string& name, 417 const base::Value* value) { 418 ExpectClearCommit(name); 419 VerifyCommit(name, value, "recommended"); 420 VerifyAndClearExpectations(); 421 } 422 423 void PreferencesBrowserTest::VerifyRollback(const std::string& name, 424 const base::Value* value, 425 const std::string& controlledBy) { 426 ExpectNoCommit(name); 427 std::stringstream javascript; 428 javascript << "testEnv.runAndReply(function() {" 429 << " Preferences.getInstance().rollbackPref(" 430 << " '" << name.c_str() << "');});"; 431 std::string observed_json; 432 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 433 render_view_host_, javascript.str(), &observed_json)); 434 VerifyObservedPref(observed_json, name, value, controlledBy, false, true); 435 VerifyAndClearExpectations(); 436 } 437 438 void PreferencesBrowserTest::StartObserving() { 439 ASSERT_TRUE(content::ExecuteScript( 440 render_view_host_, "testEnv.startObserving();")); 441 } 442 443 void PreferencesBrowserTest::FinishObserving(std::string* observed_json) { 444 ASSERT_TRUE(content::ExecuteScriptAndExtractString( 445 render_view_host_, 446 "testEnv.finishObservingAndReply();", 447 observed_json)); 448 } 449 450 void PreferencesBrowserTest::UseDefaultTestPrefs(bool includeListPref) { 451 // Boolean pref. 452 types_.push_back("Boolean"); 453 pref_names_.push_back(prefs::kAlternateErrorPagesEnabled); 454 policy_names_.push_back(policy::key::kAlternateErrorPagesEnabled); 455 non_default_values_.push_back(new base::FundamentalValue(false)); 456 457 // Integer pref. 458 types_.push_back("Integer"); 459 pref_names_.push_back(prefs::kRestoreOnStartup); 460 policy_names_.push_back(policy::key::kRestoreOnStartup); 461 non_default_values_.push_back(new base::FundamentalValue(4)); 462 463 // List pref. 464 if (includeListPref) { 465 types_.push_back("List"); 466 pref_names_.push_back(prefs::kURLsToRestoreOnStartup); 467 policy_names_.push_back(policy::key::kRestoreOnStartupURLs); 468 base::ListValue* list = new base::ListValue; 469 list->Append(new base::StringValue("http://www.google.com")); 470 list->Append(new base::StringValue("http://example.com")); 471 non_default_values_.push_back(list); 472 } 473 474 // Retrieve default values. 475 for (std::vector<std::string>::const_iterator name = pref_names_.begin(); 476 name != pref_names_.end(); ++name) { 477 default_values_.push_back( 478 pref_service_->GetDefaultPrefValue(name->c_str())->DeepCopy()); 479 } 480 } 481 482 // Verifies that initializing the JavaScript Preferences class fires the correct 483 // notifications in JavaScript. 484 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, FetchPrefs) { 485 UseDefaultTestPrefs(true); 486 std::string observed_json; 487 488 // Verify notifications when default values are in effect. 489 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 490 VerifyObservedPrefs( 491 observed_json, pref_names_, default_values_, std::string(), false, false); 492 493 // Verify notifications when recommended values are in effect. 494 SetUserPolicies(policy_names_, non_default_values_, 495 policy::POLICY_LEVEL_RECOMMENDED); 496 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 497 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, 498 "recommended", false, false); 499 500 // Verify notifications when mandatory values are in effect. 501 SetUserPolicies(policy_names_, non_default_values_, 502 policy::POLICY_LEVEL_MANDATORY); 503 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 504 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, 505 "policy", true, false); 506 507 // Verify notifications when user-modified values are in effect. 508 ClearUserPolicies(); 509 SetUserValues(pref_names_, non_default_values_); 510 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 511 VerifyObservedPrefs(observed_json, 512 pref_names_, 513 non_default_values_, 514 std::string(), 515 false, 516 false); 517 } 518 519 // Verifies that setting a user-modified pref value through the JavaScript 520 // Preferences class fires the correct notification in JavaScript and causes the 521 // change to be committed to the C++ backend. 522 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, SetPrefs) { 523 UseDefaultTestPrefs(false); 524 525 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 526 for (size_t i = 0; i < pref_names_.size(); ++i) 527 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], true); 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_, 537 policy::POLICY_LEVEL_RECOMMENDED); 538 SetUserValues(pref_names_, non_default_values_); 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 // Verifies that when the user-modified value of a dialog pref is set and the 545 // change then committed through the JavaScript Preferences class, the correct 546 // notifications fire and a commit to the C++ backend occurs in the latter step 547 // only. 548 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetCommit) { 549 UseDefaultTestPrefs(false); 550 551 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 552 for (size_t i = 0; i < pref_names_.size(); ++i) { 553 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false); 554 VerifySetCommit(pref_names_[i], non_default_values_[i]); 555 } 556 } 557 558 // Verifies that when the user-modified value of a dialog pref is set and the 559 // change then rolled back through the JavaScript Preferences class, the correct 560 // notifications fire and no commit to the C++ backend occurs. 561 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetRollback) { 562 UseDefaultTestPrefs(false); 563 564 // Verify behavior when default values are in effect. 565 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 566 for (size_t i = 0; i < pref_names_.size(); ++i) { 567 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false); 568 VerifyRollback(pref_names_[i], default_values_[i], std::string()); 569 } 570 571 // Verify behavior when recommended values are in effect. 572 SetUserPolicies(policy_names_, default_values_, 573 policy::POLICY_LEVEL_RECOMMENDED); 574 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 575 for (size_t i = 0; i < pref_names_.size(); ++i) { 576 VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false); 577 VerifyRollback(pref_names_[i], default_values_[i], "recommended"); 578 } 579 } 580 581 // Verifies that when the user-modified value of a dialog pref is cleared and 582 // the change then committed through the JavaScript Preferences class, the 583 // correct notifications fire and a commit to the C++ backend occurs in the 584 // latter step only. 585 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearCommit) { 586 UseDefaultTestPrefs(false); 587 588 SetUserPolicies(policy_names_, default_values_, 589 policy::POLICY_LEVEL_RECOMMENDED); 590 SetUserValues(pref_names_, non_default_values_); 591 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 592 for (size_t i = 0; i < pref_names_.size(); ++i) { 593 VerifyClearPref(pref_names_[i], default_values_[i], false); 594 VerifyClearCommit(pref_names_[i], default_values_[i]); 595 } 596 } 597 598 // Verifies that when the user-modified value of a dialog pref is cleared and 599 // the change then rolled back through the JavaScript Preferences class, the 600 // correct notifications fire and no commit to the C++ backend occurs. 601 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearRollback) { 602 UseDefaultTestPrefs(false); 603 604 SetUserPolicies(policy_names_, default_values_, 605 policy::POLICY_LEVEL_RECOMMENDED); 606 SetUserValues(pref_names_, non_default_values_); 607 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 608 for (size_t i = 0; i < pref_names_.size(); ++i) { 609 VerifyClearPref(pref_names_[i], default_values_[i], false); 610 VerifyRollback(pref_names_[i], non_default_values_[i], std::string()); 611 } 612 } 613 614 // Verifies that when preference values change in the C++ backend, the correct 615 // notifications fire in JavaScript. 616 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, NotificationsOnBackendChanges) { 617 UseDefaultTestPrefs(false); 618 std::string observed_json; 619 620 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 621 622 // Verify notifications when recommended values come into effect. 623 StartObserving(); 624 SetUserPolicies(policy_names_, non_default_values_, 625 policy::POLICY_LEVEL_RECOMMENDED); 626 FinishObserving(&observed_json); 627 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, 628 "recommended", false, false); 629 630 // Verify notifications when mandatory values come into effect. 631 StartObserving(); 632 SetUserPolicies(policy_names_, non_default_values_, 633 policy::POLICY_LEVEL_MANDATORY); 634 FinishObserving(&observed_json); 635 VerifyObservedPrefs(observed_json, pref_names_, non_default_values_, 636 "policy", true, false); 637 638 // Verify notifications when default values come into effect. 639 StartObserving(); 640 ClearUserPolicies(); 641 FinishObserving(&observed_json); 642 VerifyObservedPrefs( 643 observed_json, pref_names_, default_values_, std::string(), false, false); 644 645 // Verify notifications when user-modified values come into effect. 646 StartObserving(); 647 SetUserValues(pref_names_, non_default_values_); 648 FinishObserving(&observed_json); 649 VerifyObservedPrefs(observed_json, 650 pref_names_, 651 non_default_values_, 652 std::string(), 653 false, 654 false); 655 } 656 657 #if defined(OS_CHROMEOS) 658 659 // Verifies that initializing the JavaScript Preferences class fires the correct 660 // notifications in JavaScript for pref values handled by the 661 // CoreChromeOSOptionsHandler class. 662 IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ChromeOSDeviceFetchPrefs) { 663 std::vector<base::Value*> decorated_non_default_values; 664 std::string observed_json; 665 666 // Boolean pref. 667 pref_names_.push_back(chromeos::kAccountsPrefAllowGuest); 668 default_values_.push_back(new base::FundamentalValue(true)); 669 non_default_values_.push_back(new base::FundamentalValue(false)); 670 decorated_non_default_values.push_back( 671 non_default_values_.back()->DeepCopy()); 672 673 // String pref. 674 pref_names_.push_back(chromeos::kReleaseChannel); 675 default_values_.push_back(new base::StringValue("")); 676 non_default_values_.push_back(new base::StringValue("stable-channel")); 677 decorated_non_default_values.push_back( 678 non_default_values_.back()->DeepCopy()); 679 680 // List pref. 681 pref_names_.push_back(chromeos::kAccountsPrefUsers); 682 default_values_.push_back(new base::ListValue); 683 base::ListValue* list = new base::ListValue; 684 list->Append(new base::StringValue("me (at) google.com")); 685 list->Append(new base::StringValue("you (at) google.com")); 686 non_default_values_.push_back(list); 687 list = new base::ListValue; 688 base::DictionaryValue* dict = new base::DictionaryValue; 689 dict->SetString("username", "me (at) google.com"); 690 dict->SetString("name", "me (at) google.com"); 691 dict->SetString("email", ""); 692 dict->SetBoolean("owner", false); 693 list->Append(dict); 694 dict = new base::DictionaryValue; 695 dict->SetString("username", "you (at) google.com"); 696 dict->SetString("name", "you (at) google.com"); 697 dict->SetString("email", ""); 698 dict->SetBoolean("owner", false); 699 list->Append(dict); 700 decorated_non_default_values.push_back(list); 701 702 // Verify notifications when default values are in effect. 703 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 704 VerifyObservedPrefs(observed_json, pref_names_, default_values_, 705 "", true, false); 706 707 // Verify notifications when mandatory values are in effect. 708 chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get(); 709 for (size_t i = 0; i < pref_names_.size(); ++i) 710 cros_settings->Set(pref_names_[i], *non_default_values_[i]); 711 // FIXME(bartfab): Find a way to simulate enterprise enrollment in browser 712 // tests. Only if Chrome thinks that it is enrolled will the device prefs be 713 // decorated with "controlledBy: policy". 714 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 715 VerifyObservedPrefs(observed_json, pref_names_, decorated_non_default_values, 716 "", true, false); 717 718 STLDeleteElements(&decorated_non_default_values); 719 } 720 721 namespace { 722 723 const char* kUserProfilePath = "user_profile"; 724 725 } // namespace 726 727 class ProxyPreferencesBrowserTest : public PreferencesBrowserTest { 728 public: 729 virtual void SetUpOnMainThread() OVERRIDE { 730 SetupNetworkEnvironment(); 731 content::RunAllPendingInMessageLoop(); 732 733 scoped_ptr<base::DictionaryValue> proxy_config_dict( 734 ProxyConfigDictionary::CreateFixedServers("127.0.0.1:8080", 735 "*.google.com, 1.2.3.4:22")); 736 737 ProxyConfigDictionary proxy_config(proxy_config_dict.get()); 738 739 const chromeos::NetworkState* network = GetDefaultNetwork(); 740 chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config, *network); 741 742 std::string url = base::StringPrintf("%s?network=%s", 743 chrome::kChromeUIProxySettingsURL, 744 network->path().c_str()); 745 746 ui_test_utils::NavigateToURL(browser(), GURL(url)); 747 SetUpPrefs(); 748 } 749 750 protected: 751 void SetupNetworkEnvironment() { 752 chromeos::ShillProfileClient::TestInterface* profile_test = 753 chromeos::DBusThreadManager::Get()->GetShillProfileClient() 754 ->GetTestInterface(); 755 chromeos::ShillServiceClient::TestInterface* service_test = 756 chromeos::DBusThreadManager::Get()->GetShillServiceClient() 757 ->GetTestInterface(); 758 759 profile_test->AddProfile(kUserProfilePath, "user"); 760 761 service_test->ClearServices(); 762 service_test->AddService("stub_ethernet", 763 "eth0", 764 flimflam::kTypeEthernet, 765 flimflam::kStateOnline, 766 true, // add to visible 767 true); // add to watchlist 768 service_test->SetServiceProperty("stub_ethernet", 769 flimflam::kGuidProperty, 770 base::StringValue("stub_ethernet")); 771 service_test->SetServiceProperty("stub_ethernet", 772 flimflam::kProfileProperty, 773 base::StringValue(kUserProfilePath)); 774 profile_test->AddService(kUserProfilePath, "stub_wifi2"); 775 } 776 777 void SetONCPolicy(const char* policy_name, policy::PolicyScope scope) { 778 std::string onc_policy = 779 "{ \"NetworkConfigurations\": [" 780 " { \"GUID\": \"stub_ethernet\"," 781 " \"Type\": \"Ethernet\"," 782 " \"Name\": \"My Ethernet\"," 783 " \"Ethernet\": {" 784 " \"Authentication\": \"None\" }," 785 " \"ProxySettings\": {" 786 " \"PAC\": \"http://domain.com/x\"," 787 " \"Type\": \"PAC\" }" 788 " }" 789 " ]," 790 " \"Type\": \"UnencryptedConfiguration\"" 791 "}"; 792 793 policy::PolicyMap map; 794 map.Set(policy_name, 795 policy::POLICY_LEVEL_MANDATORY, 796 scope, 797 new base::StringValue(onc_policy), 798 NULL); 799 policy_provider_.UpdateChromePolicy(map); 800 801 content::RunAllPendingInMessageLoop(); 802 } 803 804 const chromeos::NetworkState* GetDefaultNetwork() { 805 return chromeos::NetworkHandler::Get()->network_state_handler() 806 ->DefaultNetwork(); 807 } 808 809 void SetProxyPref(const std::string& name, const base::Value& value) { 810 std::string type; 811 switch (value.GetType()) { 812 case base::Value::TYPE_BOOLEAN: 813 type = "Boolean"; 814 break; 815 case base::Value::TYPE_INTEGER: 816 type = "Integer"; 817 break; 818 case base::Value::TYPE_STRING: 819 type = "String"; 820 break; 821 default: 822 ASSERT_TRUE(false); 823 } 824 825 std::string observed_json; 826 SetPref(name, type, &value, true, &observed_json); 827 } 828 829 void VerifyCurrentProxyServer(const std::string& expected_server, 830 chromeos::onc::ONCSource expected_source) { 831 chromeos::onc::ONCSource actual_source; 832 scoped_ptr<ProxyConfigDictionary> proxy_dict = 833 chromeos::proxy_config::GetProxyConfigForNetwork( 834 pref_service_, 835 g_browser_process->local_state(), 836 *GetDefaultNetwork(), 837 &actual_source); 838 std::string actual_proxy_server; 839 EXPECT_TRUE(proxy_dict->GetProxyServer(&actual_proxy_server)); 840 EXPECT_EQ(expected_server, actual_proxy_server); 841 EXPECT_EQ(expected_source, actual_source); 842 } 843 }; 844 845 // Verifies that proxy settings are correctly pushed to JavaScript during 846 // initialization of the proxy settings page. 847 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSInitializeProxy) { 848 // Boolean pref. 849 pref_names_.push_back(chromeos::kProxySingle); 850 non_default_values_.push_back(new base::FundamentalValue(true)); 851 852 // Integer prefs. 853 pref_names_.push_back(chromeos::kProxySingleHttpPort); 854 non_default_values_.push_back(new base::FundamentalValue(8080)); 855 856 // String pref. 857 pref_names_.push_back(chromeos::kProxySingleHttp); 858 non_default_values_.push_back(new base::StringValue("127.0.0.1")); 859 860 // List pref. 861 pref_names_.push_back(chromeos::kProxyIgnoreList); 862 base::ListValue* list = new base::ListValue(); 863 list->Append(new base::StringValue("*.google.com")); 864 list->Append(new base::StringValue("1.2.3.4:22")); 865 non_default_values_.push_back(list); 866 867 // Verify that no policy is presented to the UI. This must be verified on the 868 // kProxyType and the kUseSharedProxies prefs. 869 pref_names_.push_back(chromeos::kProxyType); 870 non_default_values_.push_back(new base::FundamentalValue(2)); 871 872 pref_names_.push_back(prefs::kUseSharedProxies); 873 non_default_values_.push_back(new base::FundamentalValue(false)); 874 875 std::string observed_json; 876 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 877 VerifyObservedPrefs( 878 observed_json, pref_names_, non_default_values_, "", false, false); 879 } 880 881 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ONCPolicy) { 882 SetONCPolicy(policy::key::kOpenNetworkConfiguration, 883 policy::POLICY_SCOPE_USER); 884 885 // Verify that per-network policy is presented to the UI. This must be 886 // verified on the kProxyType. 887 pref_names_.push_back(chromeos::kProxyType); 888 non_default_values_.push_back(new base::FundamentalValue(3)); 889 890 std::string observed_json; 891 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 892 VerifyObservedPrefs( 893 observed_json, pref_names_, non_default_values_, "policy", true, false); 894 895 // Verify that 'use-shared-proxies' is not affected by per-network policy. 896 pref_names_.clear(); 897 STLDeleteElements(&non_default_values_); 898 pref_names_.push_back(prefs::kUseSharedProxies); 899 non_default_values_.push_back(new base::FundamentalValue(false)); 900 901 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 902 VerifyObservedPrefs( 903 observed_json, pref_names_, non_default_values_, "", false, false); 904 } 905 906 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, DeviceONCPolicy) { 907 SetONCPolicy(policy::key::kDeviceOpenNetworkConfiguration, 908 policy::POLICY_SCOPE_MACHINE); 909 910 // Verify that the policy is presented to the UI. This verification must be 911 // done on the kProxyType pref. 912 pref_names_.push_back(chromeos::kProxyType); 913 non_default_values_.push_back(new base::FundamentalValue(3)); 914 915 std::string observed_json; 916 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 917 VerifyObservedPrefs( 918 observed_json, pref_names_, non_default_values_, "policy", true, false); 919 920 // Verify that 'use-shared-proxies' is not affected by per-network policy. 921 pref_names_.clear(); 922 STLDeleteElements(&non_default_values_); 923 pref_names_.push_back(prefs::kUseSharedProxies); 924 non_default_values_.push_back(new base::FundamentalValue(false)); 925 926 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 927 VerifyObservedPrefs( 928 observed_json, pref_names_, non_default_values_, "", false, false); 929 } 930 931 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, UserProxyPolicy) { 932 policy_names_.push_back(policy::key::kProxyMode); 933 default_values_.push_back( 934 new base::StringValue(ProxyPrefs::kAutoDetectProxyModeName)); 935 SetUserPolicies( 936 policy_names_, default_values_, policy::POLICY_LEVEL_MANDATORY); 937 content::RunAllPendingInMessageLoop(); 938 939 // Verify that the policy is presented to the UI. This verification must be 940 // done on the kProxyType pref. 941 pref_names_.push_back(chromeos::kProxyType); 942 non_default_values_.push_back(new base::FundamentalValue(3)); 943 944 // Verify that 'use-shared-proxies' is controlled by the policy. 945 pref_names_.push_back(prefs::kUseSharedProxies); 946 non_default_values_.push_back(new base::FundamentalValue(false)); 947 948 std::string observed_json; 949 SetupJavaScriptTestEnvironment(pref_names_, &observed_json); 950 VerifyObservedPrefs( 951 observed_json, pref_names_, non_default_values_, "policy", true, false); 952 } 953 954 // Verifies that modifications to the proxy settings are correctly pushed from 955 // JavaScript to the ProxyConfig property stored in the network configuration. 956 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSSetProxy) { 957 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 958 959 SetProxyPref(chromeos::kProxySingleHttpPort, base::FundamentalValue(123)); 960 SetProxyPref(chromeos::kProxySingleHttp, base::StringValue("www.adomain.xy")); 961 962 VerifyCurrentProxyServer("www.adomain.xy:123", 963 chromeos::onc::ONC_SOURCE_NONE); 964 } 965 966 // Verify that default proxy ports are used and that ports can be updated 967 // without affecting the previously set hosts. 968 IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSProxyDefaultPorts) { 969 ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL)); 970 971 // Set to manual, per scheme proxy. 972 SetProxyPref(chromeos::kProxySingle, base::FundamentalValue(false)); 973 974 // Set hosts but no ports. 975 SetProxyPref(chromeos::kProxyHttpUrl, base::StringValue("a.com")); 976 SetProxyPref(chromeos::kProxyHttpsUrl, base::StringValue("4.3.2.1")); 977 SetProxyPref(chromeos::kProxyFtpUrl, base::StringValue("c.com")); 978 SetProxyPref(chromeos::kProxySocks, base::StringValue("d.com")); 979 980 // Verify default ports. 981 VerifyCurrentProxyServer( 982 "http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080", 983 chromeos::onc::ONC_SOURCE_NONE); 984 985 // Set and verify the ports. 986 SetProxyPref(chromeos::kProxyHttpPort, base::FundamentalValue(1)); 987 SetProxyPref(chromeos::kProxyHttpsPort, base::FundamentalValue(2)); 988 SetProxyPref(chromeos::kProxyFtpPort, base::FundamentalValue(3)); 989 SetProxyPref(chromeos::kProxySocksPort, base::FundamentalValue(4)); 990 991 VerifyCurrentProxyServer( 992 "http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4", 993 chromeos::onc::ONC_SOURCE_NONE); 994 } 995 996 #endif 997