blob: 444c9dbbf640c05dcf306cb43c2dbe144616051f [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/options/preferences_browsertest.h"
#include <stddef.h>
#include <iostream>
#include <memory>
#include <sstream>
#include <utility>
#include "base/callback.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/external_data_fetcher.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#if defined(OS_CHROMEOS)
#include "base/strings/stringprintf.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/net/proxy_config_handler.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/proxy_cros_settings_parser.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/stub_install_attributes.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/shill_profile_client.h"
#include "chromeos/dbus/shill_service_client.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/settings/cros_settings_names.h"
#include "components/proxy_config/proxy_config_dictionary.h"
#include "content/public/test/test_utils.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#endif
using testing::AllOf;
using testing::Mock;
using testing::Property;
using testing::Return;
using testing::_;
namespace base {
// Helper for using EXPECT_EQ() with base::Value.
bool operator==(const base::Value& first, const base::Value& second) {
return first.Equals(&second);
}
// Helper for pretty-printing the contents of base::Value in case of failures.
void PrintTo(const base::Value& value, std::ostream* stream) {
std::string json;
JSONWriter::Write(value, &json);
*stream << json;
}
} // namespace base
// Googlemock matcher for base::Value.
MATCHER_P(EqualsValue, expected, "") {
return arg && arg->Equals(expected);
}
PreferencesBrowserTest::PreferencesBrowserTest() {
}
PreferencesBrowserTest::~PreferencesBrowserTest() {
}
// Navigates to the settings page, causing the JavaScript pref handling code to
// load and injects JavaScript testing code.
void PreferencesBrowserTest::SetUpOnMainThread() {
ui_test_utils::NavigateToURL(browser(),
GURL(chrome::kChromeUISettingsFrameURL));
SetUpPrefs();
}
void PreferencesBrowserTest::SetUpPrefs() {
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
render_view_host_ = web_contents->GetRenderViewHost();
ASSERT_TRUE(render_view_host_);
pref_service_ = browser()->profile()->GetPrefs();
pref_change_registrar_.Init(pref_service_);
ASSERT_TRUE(content::ExecuteScript(render_view_host_,
"function TestEnv() {"
" this.sentinelName_ = 'download.prompt_for_download';"
" this.prefs_ = [];"
" TestEnv.instance_ = this;"
"}"
""
"TestEnv.handleEvent = function(event) {"
" var env = TestEnv.instance_;"
" var name = event.type;"
" env.removePrefListener_(name);"
" if (name == TestEnv.sentinelName_)"
" env.sentinelValue_ = event.value.value;"
" else"
" env.reply_[name] = event.value;"
" if (env.fetching_ && !--env.fetching_ ||"
" !env.fetching_ && name == env.sentinelName_) {"
" env.removePrefListeners_();"
" window.domAutomationController.send(JSON.stringify(env.reply_));"
" delete env.reply_;"
" }"
"};"
""
"TestEnv.prototype = {"
" addPrefListener_: function(name) {"
" Preferences.getInstance().addEventListener(name,"
" TestEnv.handleEvent);"
" },"
""
" addPrefListeners_: function() {"
" for (var i in this.prefs_)"
" this.addPrefListener_(this.prefs_[i]);"
" },"
""
" removePrefListener_: function(name) {"
" Preferences.getInstance().removeEventListener(name,"
" TestEnv.handleEvent);"
" },"
""
" removePrefListeners_: function() {"
" for (var i in this.prefs_)"
" this.removePrefListener_(this.prefs_[i]);"
" },"
""
""
" addPref: function(name) {"
" this.prefs_.push(name);"
" },"
""
" setupAndReply: function() {"
" this.reply_ = {};"
" Preferences.instance_ = new Preferences();"
" this.addPref(this.sentinelName_);"
" this.fetching_ = this.prefs_.length;"
" this.addPrefListeners_();"
" Preferences.getInstance().initialize();"
" },"
""
" runAndReply: function(test) {"
" this.reply_ = {};"
" this.addPrefListeners_();"
" test();"
" this.sentinelValue_ = !this.sentinelValue_;"
" Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_,"
" true);"
" },"
""
" startObserving: function() {"
" this.reply_ = {};"
" this.addPrefListeners_();"
" },"
""
" finishObservingAndReply: function() {"
" this.sentinelValue_ = !this.sentinelValue_;"
" Preferences.setBooleanPref(this.sentinelName_, this.sentinelValue_,"
" true);"
" }"
"};"));
}
// Forwards notifications received when pref values change in the backend.
void PreferencesBrowserTest::OnPreferenceChanged(const std::string& pref_name) {
OnCommit(pref_service_->FindPreference(pref_name.c_str()));
}
void PreferencesBrowserTest::SetUpInProcessBrowserTestFixture() {
// Sets up a mock policy provider for user and device policies.
EXPECT_CALL(policy_provider_, IsInitializationComplete(_))
.WillRepeatedly(Return(true));
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
&policy_provider_);
}
void PreferencesBrowserTest::SetUserPolicies(
const std::vector<std::string>& names,
const std::vector<base::Value*>& values,
policy::PolicyLevel level) {
policy::PolicyMap map;
for (size_t i = 0; i < names.size(); ++i) {
map.Set(names[i], level, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_CLOUD, values[i]->CreateDeepCopy(), nullptr);
}
policy_provider_.UpdateChromePolicy(map);
}
void PreferencesBrowserTest::ClearUserPolicies() {
policy::PolicyMap empty_policy_map;
policy_provider_.UpdateChromePolicy(empty_policy_map);
}
void PreferencesBrowserTest::SetUserValues(
const std::vector<std::string>& names,
const std::vector<base::Value*>& values) {
for (size_t i = 0; i < names.size(); ++i) {
pref_service_->Set(names[i].c_str(), *values[i]);
}
}
void PreferencesBrowserTest::VerifyKeyValue(const base::DictionaryValue& dict,
const std::string& key,
const base::Value& expected) {
const base::Value* actual = NULL;
EXPECT_TRUE(dict.Get(key, &actual)) << "Was checking key: " << key;
if (actual)
EXPECT_EQ(expected, *actual) << "Was checking key: " << key;
}
void PreferencesBrowserTest::VerifyPref(const base::DictionaryValue* prefs,
const std::string& name,
const base::Value* value,
const std::string& controlledBy,
bool disabled,
bool uncommitted) {
const base::Value* pref = NULL;
const base::DictionaryValue* dict = NULL;
ASSERT_TRUE(prefs->GetWithoutPathExpansion(name, &pref));
ASSERT_TRUE(pref->GetAsDictionary(&dict));
VerifyKeyValue(*dict, "value", *value);
if (!controlledBy.empty())
VerifyKeyValue(*dict, "controlledBy", base::StringValue(controlledBy));
else
EXPECT_FALSE(dict->HasKey("controlledBy"));
if (disabled)
VerifyKeyValue(*dict, "disabled", base::FundamentalValue(true));
else if (dict->HasKey("disabled"))
VerifyKeyValue(*dict, "disabled", base::FundamentalValue(false));
if (uncommitted)
VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(true));
else if (dict->HasKey("uncommitted"))
VerifyKeyValue(*dict, "uncommitted", base::FundamentalValue(false));
}
void PreferencesBrowserTest::VerifyObservedPref(const std::string& json,
const std::string& name,
const base::Value* value,
const std::string& controlledBy,
bool disabled,
bool uncommitted) {
std::unique_ptr<base::Value> observed_value_ptr =
base::JSONReader::Read(json);
const base::DictionaryValue* observed_dict;
ASSERT_TRUE(observed_value_ptr.get());
ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict));
VerifyPref(observed_dict, name, value, controlledBy, disabled, uncommitted);
}
void PreferencesBrowserTest::VerifyObservedPrefs(
const std::string& json,
const std::vector<std::string>& names,
const std::vector<base::Value*>& values,
const std::string& controlledBy,
bool disabled,
bool uncommitted) {
std::unique_ptr<base::Value> observed_value_ptr =
base::JSONReader::Read(json);
const base::DictionaryValue* observed_dict;
ASSERT_TRUE(observed_value_ptr.get());
ASSERT_TRUE(observed_value_ptr->GetAsDictionary(&observed_dict));
for (size_t i = 0; i < names.size(); ++i) {
VerifyPref(observed_dict, names[i], values[i], controlledBy, disabled,
uncommitted);
}
}
void PreferencesBrowserTest::ExpectNoCommit(const std::string& name) {
pref_change_registrar_.Add(
name.c_str(),
base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
base::Unretained(this)));
EXPECT_CALL(*this, OnCommit(Property(&PrefService::Preference::name, name)))
.Times(0);
}
void PreferencesBrowserTest::ExpectSetCommit(const std::string& name,
const base::Value* value) {
pref_change_registrar_.Add(
name.c_str(),
base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
base::Unretained(this)));
EXPECT_CALL(*this, OnCommit(AllOf(
Property(&PrefService::Preference::name, name),
Property(&PrefService::Preference::IsUserControlled, true),
Property(&PrefService::Preference::GetValue, EqualsValue(value)))));
}
void PreferencesBrowserTest::ExpectClearCommit(const std::string& name) {
pref_change_registrar_.Add(
name.c_str(),
base::Bind(&PreferencesBrowserTest::OnPreferenceChanged,
base::Unretained(this)));
EXPECT_CALL(*this, OnCommit(AllOf(
Property(&PrefService::Preference::name, name),
Property(&PrefService::Preference::IsUserControlled, false))));
}
void PreferencesBrowserTest::VerifyAndClearExpectations() {
Mock::VerifyAndClearExpectations(this);
pref_change_registrar_.RemoveAll();
}
void PreferencesBrowserTest::SetupJavaScriptTestEnvironment(
const std::vector<std::string>& pref_names,
std::string* observed_json) const {
std::stringstream javascript;
javascript << "var testEnv = new TestEnv();";
for (std::vector<std::string>::const_iterator name = pref_names.begin();
name != pref_names.end(); ++name) {
javascript << "testEnv.addPref('" << name->c_str() << "');";
}
javascript << "testEnv.setupAndReply();";
std::string temp_observed_json;
if (!observed_json)
observed_json = &temp_observed_json;
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
render_view_host_, javascript.str(), observed_json));
}
void PreferencesBrowserTest::SetPref(const std::string& name,
const std::string& type,
const base::Value* value,
bool commit,
std::string* observed_json) {
std::unique_ptr<base::Value> commit_ptr(new base::FundamentalValue(commit));
std::stringstream javascript;
javascript << "testEnv.runAndReply(function() {"
<< " Preferences.set" << type << "Pref("
<< " '" << name << "',"
<< " " << *value << ","
<< " " << *commit_ptr << ");"
<< "});";
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
render_view_host_, javascript.str(), observed_json));
}
void PreferencesBrowserTest::VerifySetPref(const std::string& name,
const std::string& type,
const base::Value* value,
bool commit) {
if (commit)
ExpectSetCommit(name, value);
else
ExpectNoCommit(name);
std::string observed_json;
SetPref(name, type, value, commit, &observed_json);
VerifyObservedPref(observed_json, name, value, std::string(), false, !commit);
VerifyAndClearExpectations();
}
void PreferencesBrowserTest::VerifyClearPref(const std::string& name,
const base::Value* value,
bool commit) {
if (commit)
ExpectClearCommit(name);
else
ExpectNoCommit(name);
std::string commit_json;
base::JSONWriter::Write(base::FundamentalValue(commit), &commit_json);
std::stringstream javascript;
javascript << "testEnv.runAndReply(function() {"
<< " Preferences.clearPref("
<< " '" << name.c_str() << "',"
<< " " << commit_json.c_str() << ");});";
std::string observed_json;
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
render_view_host_, javascript.str(), &observed_json));
VerifyObservedPref(observed_json, name, value, "recommended", false, !commit);
VerifyAndClearExpectations();
}
void PreferencesBrowserTest::VerifyCommit(const std::string& name,
const base::Value* value,
const std::string& controlledBy) {
std::stringstream javascript;
javascript << "testEnv.runAndReply(function() {"
<< " Preferences.getInstance().commitPref("
<< " '" << name.c_str() << "');});";
std::string observed_json;
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
render_view_host_, javascript.str(), &observed_json));
VerifyObservedPref(observed_json, name, value, controlledBy, false, false);
}
void PreferencesBrowserTest::VerifySetCommit(const std::string& name,
const base::Value* value) {
ExpectSetCommit(name, value);
VerifyCommit(name, value, std::string());
VerifyAndClearExpectations();
}
void PreferencesBrowserTest::VerifyClearCommit(const std::string& name,
const base::Value* value) {
ExpectClearCommit(name);
VerifyCommit(name, value, "recommended");
VerifyAndClearExpectations();
}
void PreferencesBrowserTest::VerifyRollback(const std::string& name,
const base::Value* value,
const std::string& controlledBy) {
ExpectNoCommit(name);
std::stringstream javascript;
javascript << "testEnv.runAndReply(function() {"
<< " Preferences.getInstance().rollbackPref("
<< " '" << name.c_str() << "');});";
std::string observed_json;
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
render_view_host_, javascript.str(), &observed_json));
VerifyObservedPref(observed_json, name, value, controlledBy, false, true);
VerifyAndClearExpectations();
}
void PreferencesBrowserTest::StartObserving() {
ASSERT_TRUE(content::ExecuteScript(
render_view_host_, "testEnv.startObserving();"));
}
void PreferencesBrowserTest::FinishObserving(std::string* observed_json) {
ASSERT_TRUE(content::ExecuteScriptAndExtractString(
render_view_host_,
"testEnv.finishObservingAndReply();",
observed_json));
}
void PreferencesBrowserTest::UseDefaultTestPrefs(bool includeListPref) {
// Boolean pref.
types_.push_back("Boolean");
pref_names_.push_back(prefs::kAlternateErrorPagesEnabled);
policy_names_.push_back(policy::key::kAlternateErrorPagesEnabled);
non_default_values_.push_back(new base::FundamentalValue(false));
// Integer pref.
types_.push_back("Integer");
pref_names_.push_back(prefs::kRestoreOnStartup);
policy_names_.push_back(policy::key::kRestoreOnStartup);
non_default_values_.push_back(new base::FundamentalValue(4));
// List pref.
if (includeListPref) {
types_.push_back("List");
pref_names_.push_back(prefs::kURLsToRestoreOnStartup);
policy_names_.push_back(policy::key::kRestoreOnStartupURLs);
base::ListValue* list = new base::ListValue;
list->AppendString("http://www.example.com");
list->AppendString("http://example.com");
non_default_values_.push_back(list);
}
// Retrieve default values.
for (std::vector<std::string>::const_iterator name = pref_names_.begin();
name != pref_names_.end(); ++name) {
default_values_.push_back(
pref_service_->GetDefaultPrefValue(name->c_str())->DeepCopy());
}
}
// Verifies that initializing the JavaScript Preferences class fires the correct
// notifications in JavaScript.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, FetchPrefs) {
UseDefaultTestPrefs(true);
std::string observed_json;
// Verify notifications when default values are in effect.
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, default_values_.get(),
std::string(), false, false);
// Verify notifications when recommended values are in effect.
SetUserPolicies(policy_names_, non_default_values_.get(),
policy::POLICY_LEVEL_RECOMMENDED);
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(),
"recommended", false, false);
// Verify notifications when mandatory values are in effect.
SetUserPolicies(policy_names_, non_default_values_.get(),
policy::POLICY_LEVEL_MANDATORY);
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(),
"policy", true, false);
// Verify notifications when user-modified values are in effect.
ClearUserPolicies();
SetUserValues(pref_names_, non_default_values_.get());
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json,
pref_names_,
non_default_values_.get(),
std::string(),
false,
false);
}
// Verifies that setting a user-modified pref value through the JavaScript
// Preferences class fires the correct notification in JavaScript and causes the
// change to be committed to the C++ backend.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, SetPrefs) {
UseDefaultTestPrefs(false);
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], true);
}
}
// Verifies that clearing a user-modified pref value through the JavaScript
// Preferences class fires the correct notification in JavaScript and causes the
// change to be committed to the C++ backend.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ClearPrefs) {
UseDefaultTestPrefs(false);
SetUserPolicies(policy_names_, default_values_.get(),
policy::POLICY_LEVEL_RECOMMENDED);
SetUserValues(pref_names_, non_default_values_.get());
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifyClearPref(pref_names_[i], default_values_[i], true);
}
}
// Verifies that when the user-modified value of a dialog pref is set and the
// change then committed through the JavaScript Preferences class, the correct
// notifications fire and a commit to the C++ backend occurs in the latter step
// only.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetCommit) {
UseDefaultTestPrefs(false);
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
VerifySetCommit(pref_names_[i], non_default_values_[i]);
}
}
// Verifies that when the user-modified value of a dialog pref is set and the
// change then rolled back through the JavaScript Preferences class, the correct
// notifications fire and no commit to the C++ backend occurs.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsSetRollback) {
UseDefaultTestPrefs(false);
// Verify behavior when default values are in effect.
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
VerifyRollback(pref_names_[i], default_values_[i], std::string());
}
// Verify behavior when recommended values are in effect.
SetUserPolicies(policy_names_, default_values_.get(),
policy::POLICY_LEVEL_RECOMMENDED);
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifySetPref(pref_names_[i], types_[i], non_default_values_[i], false);
VerifyRollback(pref_names_[i], default_values_[i], "recommended");
}
}
// Verifies that when the user-modified value of a dialog pref is cleared and
// the change then committed through the JavaScript Preferences class, the
// correct notifications fire and a commit to the C++ backend occurs in the
// latter step only.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearCommit) {
UseDefaultTestPrefs(false);
SetUserPolicies(policy_names_, default_values_.get(),
policy::POLICY_LEVEL_RECOMMENDED);
SetUserValues(pref_names_, non_default_values_.get());
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifyClearPref(pref_names_[i], default_values_[i], false);
VerifyClearCommit(pref_names_[i], default_values_[i]);
}
}
// Verifies that when the user-modified value of a dialog pref is cleared and
// the change then rolled back through the JavaScript Preferences class, the
// correct notifications fire and no commit to the C++ backend occurs.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, DialogPrefsClearRollback) {
UseDefaultTestPrefs(false);
SetUserPolicies(policy_names_, default_values_.get(),
policy::POLICY_LEVEL_RECOMMENDED);
SetUserValues(pref_names_, non_default_values_.get());
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
for (size_t i = 0; i < pref_names_.size(); ++i) {
VerifyClearPref(pref_names_[i], default_values_[i], false);
VerifyRollback(pref_names_[i], non_default_values_[i], std::string());
}
}
// Verifies that when preference values change in the C++ backend, the correct
// notifications fire in JavaScript.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, NotificationsOnBackendChanges) {
UseDefaultTestPrefs(false);
std::string observed_json;
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
// Verify notifications when recommended values come into effect.
StartObserving();
SetUserPolicies(policy_names_, non_default_values_.get(),
policy::POLICY_LEVEL_RECOMMENDED);
FinishObserving(&observed_json);
VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(),
"recommended", false, false);
// Verify notifications when mandatory values come into effect.
StartObserving();
SetUserPolicies(policy_names_, non_default_values_.get(),
policy::POLICY_LEVEL_MANDATORY);
FinishObserving(&observed_json);
VerifyObservedPrefs(observed_json, pref_names_, non_default_values_.get(),
"policy", true, false);
// Verify notifications when default values come into effect.
StartObserving();
ClearUserPolicies();
FinishObserving(&observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, default_values_.get(),
std::string(), false, false);
// Verify notifications when user-modified values come into effect.
StartObserving();
SetUserValues(pref_names_, non_default_values_.get());
FinishObserving(&observed_json);
VerifyObservedPrefs(observed_json,
pref_names_,
non_default_values_.get(),
std::string(),
false,
false);
}
#if defined(OS_CHROMEOS)
// Verifies that initializing the JavaScript Preferences class fires the correct
// notifications in JavaScript for pref values handled by the
// CoreChromeOSOptionsHandler class.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest, ChromeOSDeviceFetchPrefs) {
std::string observed_json;
// Boolean pref.
pref_names_.push_back(chromeos::kAccountsPrefAllowGuest);
default_values_.push_back(new base::FundamentalValue(true));
// String pref.
pref_names_.push_back(chromeos::kReleaseChannel);
default_values_.push_back(new base::StringValue(""));
// List pref.
pref_names_.push_back(chromeos::kAccountsPrefUsers);
default_values_.push_back(new base::ListValue);
// Verify notifications when default values are in effect.
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_, default_values_.get(),
"owner", true, false);
}
// Verifies that initializing the JavaScript Preferences class fires the correct
// notifications in JavaScript for non-privileged pref values handled by the
// CoreChromeOSOptionsHandler class.
IN_PROC_BROWSER_TEST_F(PreferencesBrowserTest,
ChromeOSDeviceFetchNonPrivilegedPrefs) {
ScopedVector<base::Value> decorated_non_default_values;
std::string observed_json;
// Non-privileged string pref.
pref_names_.push_back(chromeos::kSystemTimezone);
default_values_.push_back(new base::StringValue("America/Los_Angeles"));
non_default_values_.push_back(new base::StringValue("America/New_York"));
decorated_non_default_values.push_back(
non_default_values_.back()->DeepCopy());
// Verify notifications when default values are in effect.
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_, default_values_.get(),
std::string(), false, false);
chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
cros_settings->Set(pref_names_[0], *non_default_values_[0]);
// Verify notifications when non-default values are in effect.
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_,
decorated_non_default_values.get(),
std::string(), false, false);
}
class ManagedPreferencesBrowserTest : public PreferencesBrowserTest {
protected:
// PreferencesBrowserTest implementation:
void SetUpInProcessBrowserTestFixture() override {
// Set up fake install attributes.
std::unique_ptr<chromeos::StubInstallAttributes> attributes =
base::MakeUnique<chromeos::StubInstallAttributes>();
attributes->SetDomain("example.com");
attributes->SetRegistrationUser("user@example.com");
policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
attributes.release());
PreferencesBrowserTest::SetUpInProcessBrowserTestFixture();
}
};
// Verifies that initializing the JavaScript Preferences class fires the correct
// notifications in JavaScript for pref values handled by the
// CoreChromeOSOptionsHandler class for a managed device.
IN_PROC_BROWSER_TEST_F(ManagedPreferencesBrowserTest,
ChromeOSDeviceFetchPrefs) {
ScopedVector<base::Value> decorated_non_default_values;
std::string observed_json;
// Boolean pref.
pref_names_.push_back(chromeos::kAccountsPrefAllowGuest);
non_default_values_.push_back(new base::FundamentalValue(false));
decorated_non_default_values.push_back(
non_default_values_.back()->DeepCopy());
// String pref.
pref_names_.push_back(chromeos::kReleaseChannel);
non_default_values_.push_back(new base::StringValue("stable-channel"));
decorated_non_default_values.push_back(
non_default_values_.back()->DeepCopy());
// List pref.
pref_names_.push_back(chromeos::kAccountsPrefUsers);
base::ListValue* list = new base::ListValue;
list->AppendString("me@google.com");
list->AppendString("you@google.com");
non_default_values_.push_back(list);
list = new base::ListValue;
auto dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString("username", "me@google.com");
dict->SetString("name", "me@google.com");
dict->SetString("email", "");
dict->SetBoolean("owner", false);
list->Append(std::move(dict));
dict = base::MakeUnique<base::DictionaryValue>();
dict->SetString("username", "you@google.com");
dict->SetString("name", "you@google.com");
dict->SetString("email", "");
dict->SetBoolean("owner", false);
list->Append(std::move(dict));
decorated_non_default_values.push_back(list);
chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
for (size_t i = 0; i < pref_names_.size(); ++i) {
cros_settings->Set(pref_names_[i], *non_default_values_[i]);
}
// Verify notifications when mandatory values are in effect.
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_,
decorated_non_default_values.get(),
"policy", true, false);
}
// Verifies that initializing the JavaScript Preferences class fires the correct
// notifications in JavaScript for non-privileged pref values handled by the
// CoreChromeOSOptionsHandler class for a managed device.
IN_PROC_BROWSER_TEST_F(ManagedPreferencesBrowserTest,
ChromeOSDeviceFetchNonPrivilegedPrefs) {
ScopedVector<base::Value> decorated_non_default_values;
std::string observed_json;
// Non-privileged string pref.
pref_names_.push_back(chromeos::kSystemTimezone);
non_default_values_.push_back(new base::StringValue("America/New_York"));
decorated_non_default_values.push_back(
non_default_values_.back()->DeepCopy());
// Verify notifications when mandatory values are in effect.
chromeos::CrosSettings* cros_settings = chromeos::CrosSettings::Get();
cros_settings->Set(pref_names_[0], *non_default_values_[0]);
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(observed_json, pref_names_,
decorated_non_default_values.get(),
std::string(), false, false);
}
namespace {
const char* kUserProfilePath = "user_profile";
} // namespace
class ProxyPreferencesBrowserTest : public PreferencesBrowserTest {
public:
void SetUpOnMainThread() override {
SetupNetworkEnvironment();
content::RunAllPendingInMessageLoop();
std::unique_ptr<base::DictionaryValue> proxy_config_dict(
ProxyConfigDictionary::CreateFixedServers("127.0.0.1:8080",
"*.google.com, 1.2.3.4:22"));
ProxyConfigDictionary proxy_config(proxy_config_dict.get());
const chromeos::NetworkState* network = GetDefaultNetwork();
ASSERT_TRUE(network);
chromeos::proxy_config::SetProxyConfigForNetwork(proxy_config, *network);
std::string url = base::StringPrintf("%s?network=%s",
chrome::kChromeUIProxySettingsURL,
network->guid().c_str());
ui_test_utils::NavigateToURL(browser(), GURL(url));
SetUpPrefs();
}
protected:
void SetupNetworkEnvironment() {
chromeos::ShillProfileClient::TestInterface* profile_test =
chromeos::DBusThreadManager::Get()->GetShillProfileClient()
->GetTestInterface();
chromeos::ShillServiceClient::TestInterface* service_test =
chromeos::DBusThreadManager::Get()->GetShillServiceClient()
->GetTestInterface();
profile_test->AddProfile(kUserProfilePath, "user");
service_test->ClearServices();
service_test->AddService("stub_ethernet",
"stub_ethernet_guid",
"eth0",
shill::kTypeEthernet,
shill::kStateOnline,
true /* add_to_visible */ );
service_test->SetServiceProperty("stub_ethernet",
shill::kProfileProperty,
base::StringValue(kUserProfilePath));
profile_test->AddService(kUserProfilePath, "stub_wifi2");
}
void SetONCPolicy(const char* policy_name, policy::PolicyScope scope) {
std::string onc_policy =
"{ \"NetworkConfigurations\": ["
" { \"GUID\": \"stub_ethernet_guid\","
" \"Type\": \"Ethernet\","
" \"Name\": \"My Ethernet\","
" \"Ethernet\": {"
" \"Authentication\": \"None\" },"
" \"ProxySettings\": {"
" \"PAC\": \"http://domain.com/x\","
" \"Type\": \"PAC\" }"
" }"
" ],"
" \"Type\": \"UnencryptedConfiguration\""
"}";
policy::PolicyMap map;
map.Set(policy_name, policy::POLICY_LEVEL_MANDATORY, scope,
policy::POLICY_SOURCE_CLOUD,
base::MakeUnique<base::StringValue>(onc_policy), nullptr);
policy_provider_.UpdateChromePolicy(map);
content::RunAllPendingInMessageLoop();
}
const chromeos::NetworkState* GetDefaultNetwork() {
chromeos::NetworkStateHandler* handler =
chromeos::NetworkHandler::Get()->network_state_handler();
return handler->DefaultNetwork();
}
void SetProxyPref(const std::string& name, const base::Value& value) {
std::string type;
switch (value.GetType()) {
case base::Value::TYPE_BOOLEAN:
type = "Boolean";
break;
case base::Value::TYPE_INTEGER:
type = "Integer";
break;
case base::Value::TYPE_STRING:
type = "String";
break;
default:
ASSERT_TRUE(false);
}
std::string observed_json;
SetPref(name, type, &value, true, &observed_json);
}
void VerifyCurrentProxyServer(const std::string& expected_server,
onc::ONCSource expected_source) {
const chromeos::NetworkState* network = GetDefaultNetwork();
ASSERT_TRUE(network);
onc::ONCSource actual_source;
std::unique_ptr<ProxyConfigDictionary> proxy_dict =
chromeos::proxy_config::GetProxyConfigForNetwork(
pref_service_, g_browser_process->local_state(), *network,
&actual_source);
ASSERT_TRUE(proxy_dict);
std::string actual_proxy_server;
EXPECT_TRUE(proxy_dict->GetProxyServer(&actual_proxy_server));
EXPECT_EQ(expected_server, actual_proxy_server);
EXPECT_EQ(expected_source, actual_source);
}
};
// Verifies that proxy settings are correctly pushed to JavaScript during
// initialization of the proxy settings page.
IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSInitializeProxy) {
// Boolean pref.
pref_names_.push_back(chromeos::kProxySingle);
non_default_values_.push_back(new base::FundamentalValue(true));
// Integer prefs.
pref_names_.push_back(chromeos::kProxySingleHttpPort);
non_default_values_.push_back(new base::FundamentalValue(8080));
// String pref.
pref_names_.push_back(chromeos::kProxySingleHttp);
non_default_values_.push_back(new base::StringValue("127.0.0.1"));
// List pref.
pref_names_.push_back(chromeos::kProxyIgnoreList);
base::ListValue* list = new base::ListValue();
list->AppendString("*.google.com");
list->AppendString("1.2.3.4:22");
non_default_values_.push_back(list);
// Verify that no policy is presented to the UI. This must be verified on the
// kProxyType and the kUseSharedProxies prefs.
pref_names_.push_back(chromeos::kProxyType);
non_default_values_.push_back(new base::FundamentalValue(2));
pref_names_.push_back(prefs::kUseSharedProxies);
non_default_values_.push_back(new base::FundamentalValue(false));
std::string observed_json;
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, non_default_values_.get(), "", false, false);
}
IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ONCPolicy) {
SetONCPolicy(policy::key::kOpenNetworkConfiguration,
policy::POLICY_SCOPE_USER);
// Verify that per-network policy is presented to the UI. This must be
// verified on the kProxyType.
pref_names_.push_back(chromeos::kProxyType);
non_default_values_.push_back(new base::FundamentalValue(3));
std::string observed_json;
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, non_default_values_.get(),
"policy", true, false);
// Verify that 'use-shared-proxies' is not affected by per-network policy.
pref_names_.clear();
non_default_values_.clear();
pref_names_.push_back(prefs::kUseSharedProxies);
non_default_values_.push_back(new base::FundamentalValue(false));
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, non_default_values_.get(), "", false, false);
}
IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, DeviceONCPolicy) {
SetONCPolicy(policy::key::kDeviceOpenNetworkConfiguration,
policy::POLICY_SCOPE_MACHINE);
// Verify that the policy is presented to the UI. This verification must be
// done on the kProxyType pref.
pref_names_.push_back(chromeos::kProxyType);
non_default_values_.push_back(new base::FundamentalValue(3));
std::string observed_json;
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, non_default_values_.get(),
"policy", true, false);
// Verify that 'use-shared-proxies' is not affected by per-network policy.
pref_names_.clear();
non_default_values_.clear();
pref_names_.push_back(prefs::kUseSharedProxies);
non_default_values_.push_back(new base::FundamentalValue(false));
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, non_default_values_.get(), "", false, false);
}
IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, UserProxyPolicy) {
policy_names_.push_back(policy::key::kProxyMode);
default_values_.push_back(
new base::StringValue(ProxyPrefs::kAutoDetectProxyModeName));
SetUserPolicies(
policy_names_, default_values_.get(), policy::POLICY_LEVEL_MANDATORY);
content::RunAllPendingInMessageLoop();
// Verify that the policy is presented to the UI. This verification must be
// done on the kProxyType pref.
pref_names_.push_back(chromeos::kProxyType);
non_default_values_.push_back(new base::FundamentalValue(3));
// Verify that 'use-shared-proxies' is controlled by the policy.
pref_names_.push_back(prefs::kUseSharedProxies);
non_default_values_.push_back(new base::FundamentalValue(false));
std::string observed_json;
SetupJavaScriptTestEnvironment(pref_names_, &observed_json);
VerifyObservedPrefs(
observed_json, pref_names_, non_default_values_.get(),
"policy", true, false);
}
// Verifies that modifications to the proxy settings are correctly pushed from
// JavaScript to the ProxyConfig property stored in the network configuration.
IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSSetProxy) {
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
SetProxyPref(chromeos::kProxySingleHttpPort, base::FundamentalValue(123));
SetProxyPref(chromeos::kProxySingleHttp, base::StringValue("www.adomain.xy"));
VerifyCurrentProxyServer("www.adomain.xy:123",
onc::ONC_SOURCE_NONE);
}
// Verify that default proxy ports are used and that ports can be updated
// without affecting the previously set hosts.
IN_PROC_BROWSER_TEST_F(ProxyPreferencesBrowserTest, ChromeOSProxyDefaultPorts) {
ASSERT_NO_FATAL_FAILURE(SetupJavaScriptTestEnvironment(pref_names_, NULL));
// Set to manual, per scheme proxy.
SetProxyPref(chromeos::kProxySingle, base::FundamentalValue(false));
// Set hosts but no ports.
SetProxyPref(chromeos::kProxyHttpUrl, base::StringValue("a.com"));
SetProxyPref(chromeos::kProxyHttpsUrl, base::StringValue("4.3.2.1"));
SetProxyPref(chromeos::kProxyFtpUrl, base::StringValue("c.com"));
SetProxyPref(chromeos::kProxySocks, base::StringValue("d.com"));
// Verify default ports.
VerifyCurrentProxyServer(
"http=a.com:80;https=4.3.2.1:80;ftp=c.com:80;socks=socks4://d.com:1080",
onc::ONC_SOURCE_NONE);
// Set and verify the ports.
SetProxyPref(chromeos::kProxyHttpPort, base::FundamentalValue(1));
SetProxyPref(chromeos::kProxyHttpsPort, base::FundamentalValue(2));
SetProxyPref(chromeos::kProxyFtpPort, base::FundamentalValue(3));
SetProxyPref(chromeos::kProxySocksPort, base::FundamentalValue(4));
VerifyCurrentProxyServer(
"http=a.com:1;https=4.3.2.1:2;ftp=c.com:3;socks=socks4://d.com:4",
onc::ONC_SOURCE_NONE);
}
#endif