// 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 #include #include #include #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& 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 settings_pages_; std::vector 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 TestCaseMap; typedef TestCaseMap::const_iterator iterator; TestCases() { test_cases_ = new std::map(); 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 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 {}; // 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 {}; 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& 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