blob: f8ad5560fadad4c0b999f22069401cb14f035aed [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 <algorithm>
#include <map>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/mock_configuration_policy_provider.h"
#include "chrome/browser/policy/policy_map.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "googleurl/src/gurl.h"
#include "policy/policy_constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Return;
namespace policy {
namespace {
const char* kSettingsPages[] = {
"chrome://settings-frame",
"chrome://settings-frame/searchEngines",
"chrome://settings-frame/passwords",
"chrome://settings-frame/autofill",
"chrome://settings-frame/content",
"chrome://settings-frame/homePageOverlay",
"chrome://settings-frame/languages",
#if defined(OS_CHROMEOS)
"chrome://settings-frame/accounts",
#endif
};
// Contains the testing details for a single policy, loaded from
// chrome/test/data/policy/policy_test_cases.json.
class PolicyTestCase {
public:
explicit PolicyTestCase(const std::string& name)
: name_(name),
is_local_state_(false),
official_only_(false) {}
~PolicyTestCase() {}
const std::string& name() const { return name_; }
void set_pref(const std::string& pref) { pref_ = pref; }
const std::string& pref() const { return pref_; }
const char* pref_name() const { return pref_.c_str(); }
const PolicyMap& test_policy() const { return test_policy_; }
void set_test_policy(const PolicyMap& policy) {
test_policy_.CopyFrom(policy);
}
const std::vector<GURL>& settings_pages() const { return settings_pages_; }
void AddSettingsPage(const GURL& url) { settings_pages_.push_back(url); }
bool IsOsSupported() const {
#if defined(OS_WIN)
const std::string os("win");
#elif defined(OS_MACOSX)
const std::string os("mac");
#elif defined(OS_CHROMEOS)
const std::string os("chromeos");
#elif defined(OS_LINUX)
const std::string os("linux");
#else
#error "Unknown platform"
#endif
return std::find(supported_os_.begin(), supported_os_.end(), os) !=
supported_os_.end();
}
void AddSupportedOs(const std::string& os) { supported_os_.push_back(os); }
bool is_local_state() const { return is_local_state_; }
void set_local_state(bool flag) { is_local_state_ = flag; }
bool is_official_only() const { return official_only_; }
void set_official_only(bool flag) { official_only_ = flag; }
bool IsSupported() const {
#if !defined(OFFICIAL_BUILD)
if (is_official_only())
return false;
#endif
return IsOsSupported();
}
private:
std::string name_;
std::string pref_;
PolicyMap test_policy_;
std::vector<GURL> settings_pages_;
std::vector<std::string> supported_os_;
bool is_local_state_;
bool official_only_;
DISALLOW_COPY_AND_ASSIGN(PolicyTestCase);
};
// Parses all the test cases and makes then available in a map.
class TestCases {
public:
typedef std::map<std::string, PolicyTestCase*> TestCaseMap;
typedef TestCaseMap::const_iterator iterator;
TestCases() {
test_cases_ = new std::map<std::string, PolicyTestCase*>();
FilePath path = ui_test_utils::GetTestFilePath(
FilePath(FILE_PATH_LITERAL("policy")),
FilePath(FILE_PATH_LITERAL("policy_test_cases.json")));
std::string json;
if (!file_util::ReadFileToString(path, &json)) {
ADD_FAILURE();
return;
}
int error_code = -1;
std::string error_string;
base::DictionaryValue* dict = NULL;
scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
json, base::JSON_PARSE_RFC, &error_code, &error_string));
if (!value.get() || !value->GetAsDictionary(&dict)) {
ADD_FAILURE() << "Error parsing policy_test_cases.json: " << error_string;
return;
}
const PolicyDefinitionList* list = GetChromePolicyDefinitionList();
for (const PolicyDefinitionList::Entry* policy = list->begin;
policy != list->end; ++policy) {
PolicyTestCase* test_case = GetTestCase(dict, policy->name);
if (test_case)
(*test_cases_)[policy->name] = test_case;
}
}
~TestCases() {
STLDeleteValues(test_cases_);
delete test_cases_;
}
const PolicyTestCase* Get(const std::string& name) {
iterator it = test_cases_->find(name);
return it == end() ? NULL : it->second;
}
const TestCaseMap& map() const { return *test_cases_; }
iterator begin() const { return test_cases_->begin(); }
iterator end() const { return test_cases_->end(); }
private:
PolicyTestCase* GetTestCase(const base::DictionaryValue* tests,
const std::string& name) {
const base::DictionaryValue* dict = NULL;
if (!tests->GetDictionary(name, &dict))
return NULL;
PolicyTestCase* test_case = new PolicyTestCase(name);
std::string pref;
if (dict->GetString("pref", &pref))
test_case->set_pref(pref);
const base::DictionaryValue* policy_dict = NULL;
if (dict->GetDictionary("test_policy", &policy_dict)) {
PolicyMap policies;
policies.LoadFrom(policy_dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
test_case->set_test_policy(policies);
}
const base::ListValue* settings_pages = NULL;
if (dict->GetList("settings_pages", &settings_pages)) {
for (size_t i = 0; i < settings_pages->GetSize(); ++i) {
std::string page;
if (settings_pages->GetString(i, &page))
test_case->AddSettingsPage(GURL(page));
}
}
const base::ListValue* supported_os = NULL;
if (dict->GetList("os", &supported_os)) {
for (size_t i = 0; i < supported_os->GetSize(); ++i) {
std::string os;
if (supported_os->GetString(i, &os))
test_case->AddSupportedOs(os);
}
}
bool flag = false;
if (dict->GetBoolean("local_state", &flag))
test_case->set_local_state(flag);
if (dict->GetBoolean("official_only", &flag))
test_case->set_official_only(flag);
return test_case;
}
TestCaseMap* test_cases_;
DISALLOW_COPY_AND_ASSIGN(TestCases);
};
bool IsBannerVisible(Browser* browser) {
content::WebContents* contents = chrome::GetActiveWebContents(browser);
bool result = false;
EXPECT_TRUE(content::ExecuteJavaScriptAndExtractBool(
contents->GetRenderViewHost(),
std::wstring(),
L"var visible = false;"
L"var banners = document.querySelectorAll('.page-banner');"
L"for (var i = 0; i < banners.length; i++) {"
L" if (banners[i].parentElement.id == 'templates')"
L" continue;"
L" if (window.getComputedStyle(banners[i]).display != 'none')"
L" visible = true;"
L"}"
L"domAutomationController.send(visible);",
&result));
return result;
}
} // namespace
// A class of tests parameterized by a settings page URL.
class PolicyPrefsSettingsBannerTest
: public InProcessBrowserTest,
public testing::WithParamInterface<const char*> {};
// Base class for tests that change policies.
class PolicyBaseTest : public InProcessBrowserTest {
protected:
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
EXPECT_CALL(provider_, IsInitializationComplete())
.WillRepeatedly(Return(true));
BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
}
TestCases test_cases_;
MockConfigurationPolicyProvider provider_;
};
// A class of tests that change policy and don't need parameters.
class PolicyPrefsBannerTest : public PolicyBaseTest {};
// A class of tests that change policy and are parameterized with a policy
// definition.
class PolicyPrefsTest
: public PolicyBaseTest,
public testing::WithParamInterface<PolicyDefinitionList::Entry> {};
TEST(PolicyPrefsTest, AllPoliciesHaveATestCase) {
// Verifies that all known policies have a test case in the JSON file.
// This test fails when a policy is added to
// chrome/app/policy/policy_templates.json but a test case is not added to
// chrome/test/data/policy/policy_test_cases.json.
TestCases test_cases;
const PolicyDefinitionList* list = GetChromePolicyDefinitionList();
for (const PolicyDefinitionList::Entry* policy = list->begin;
policy != list->end; ++policy) {
EXPECT_TRUE(ContainsKey(test_cases.map(), policy->name))
<< "Missing policy test case for: " << policy->name;
}
}
IN_PROC_BROWSER_TEST_P(PolicyPrefsSettingsBannerTest, NoPoliciesNoBanner) {
// Verifies that the banner isn't shown in the settings UI when no policies
// are set.
ui_test_utils::NavigateToURL(browser(), GURL(GetParam()));
EXPECT_FALSE(IsBannerVisible(browser()));
}
INSTANTIATE_TEST_CASE_P(PolicyPrefsSettingsBannerTestInstance,
PolicyPrefsSettingsBannerTest,
testing::ValuesIn(kSettingsPages));
IN_PROC_BROWSER_TEST_F(PolicyPrefsBannerTest, TogglePolicyTogglesBanner) {
// Verifies that the banner appears and disappears as policies are added and
// removed.
// |test_case| is just a particular policy that should trigger the banner
// on the main settings page.
const PolicyTestCase* test_case = test_cases_.Get("ShowHomeButton");
ASSERT_TRUE(test_case);
// No banner by default.
ui_test_utils::NavigateToURL(browser(), GURL(kSettingsPages[0]));
EXPECT_FALSE(IsBannerVisible(browser()));
// Adding a policy makes the banner show up.
provider_.UpdateChromePolicy(test_case->test_policy());
EXPECT_TRUE(IsBannerVisible(browser()));
// And removing it makes the banner go away.
const PolicyMap kNoPolicies;
provider_.UpdateChromePolicy(kNoPolicies);
EXPECT_FALSE(IsBannerVisible(browser()));
// Do it again, just in case.
provider_.UpdateChromePolicy(test_case->test_policy());
EXPECT_TRUE(IsBannerVisible(browser()));
provider_.UpdateChromePolicy(kNoPolicies);
EXPECT_FALSE(IsBannerVisible(browser()));
}
IN_PROC_BROWSER_TEST_P(PolicyPrefsTest, PolicyToPrefsMapping) {
// Verifies that policies make their corresponding preferences become managed,
// and that the user can't override that setting.
const PolicyTestCase* test_case = test_cases_.Get(GetParam().name);
ASSERT_TRUE(test_case);
if (!test_case->IsSupported() || test_case->pref().empty())
return;
LOG(INFO) << "Testing policy: " << test_case->name();
PrefService* prefs = test_case->is_local_state() ?
g_browser_process->local_state() : browser()->profile()->GetPrefs();
// The preference must have been registered.
const PrefService::Preference* pref =
prefs->FindPreference(test_case->pref_name());
ASSERT_TRUE(pref);
prefs->ClearPref(test_case->pref_name());
// Verify that setting the policy overrides the pref.
EXPECT_TRUE(pref->IsDefaultValue());
EXPECT_TRUE(pref->IsUserModifiable());
EXPECT_FALSE(pref->IsUserControlled());
EXPECT_FALSE(pref->IsManaged());
provider_.UpdateChromePolicy(test_case->test_policy());
EXPECT_FALSE(pref->IsDefaultValue());
EXPECT_FALSE(pref->IsUserModifiable());
EXPECT_FALSE(pref->IsUserControlled());
EXPECT_TRUE(pref->IsManaged());
}
IN_PROC_BROWSER_TEST_P(PolicyPrefsTest, CheckAllPoliciesThatShowTheBanner) {
// Verifies that the banner appears for each policy that affects a control
// in the settings UI.
const PolicyTestCase* test_case = test_cases_.Get(GetParam().name);
ASSERT_TRUE(test_case);
if (!test_case->IsSupported() || test_case->settings_pages().empty())
return;
LOG(INFO) << "Testing policy: " << test_case->name();
const std::vector<GURL>& pages = test_case->settings_pages();
for (size_t i = 0; i < pages.size(); ++i) {
ui_test_utils::NavigateToURL(browser(), pages[i]);
EXPECT_FALSE(IsBannerVisible(browser()));
provider_.UpdateChromePolicy(test_case->test_policy());
EXPECT_TRUE(IsBannerVisible(browser()));
const PolicyMap kNoPolicies;
provider_.UpdateChromePolicy(kNoPolicies);
EXPECT_FALSE(IsBannerVisible(browser()));
}
}
INSTANTIATE_TEST_CASE_P(
PolicyPrefsTestInstance,
PolicyPrefsTest,
testing::ValuesIn(GetChromePolicyDefinitionList()->begin,
GetChromePolicyDefinitionList()->end));
} // namespace policy