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.
12 #include "base/basictypes.h"
13 #include "base/file_util.h"
14 #include "base/files/file_path.h"
15 #include "base/json/json_reader.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/scoped_vector.h"
19 #include "base/memory/weak_ptr.h"
20 #include "base/prefs/pref_service.h"
21 #include "base/run_loop.h"
22 #include "base/stl_util.h"
23 #include "base/strings/string_util.h"
24 #include "base/strings/utf_string_conversions.h"
25 #include "base/values.h"
26 #include "chrome/browser/browser_process.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/search_engines/template_url_service_factory.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/tabs/tab_strip_model.h"
31 #include "chrome/test/base/in_process_browser_test.h"
32 #include "chrome/test/base/ui_test_utils.h"
33 #include "components/policy/core/browser/browser_policy_connector.h"
34 #include "components/policy/core/common/external_data_fetcher.h"
35 #include "components/policy/core/common/external_data_manager.h"
36 #include "components/policy/core/common/mock_configuration_policy_provider.h"
37 #include "components/policy/core/common/policy_details.h"
38 #include "components/policy/core/common/policy_map.h"
39 #include "components/policy/core/common/schema.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/test/browser_test_utils.h"
42 #include "policy/policy_constants.h"
43 #include "testing/gmock/include/gmock/gmock.h"
44 #include "testing/gtest/include/gtest/gtest.h"
47 using testing::Return;
54 const char kMainSettingsPage[] = "chrome://settings-frame";
56 const char kCrosSettingsPrefix[] = "cros.";
58 // Contains the details of a single test case verifying that the controlled
59 // setting indicators for a pref affected by a policy work correctly. This is
60 // part of the data loaded from chrome/test/data/policy/policy_test_cases.json.
61 class IndicatorTestCase {
63 IndicatorTestCase(const base::DictionaryValue& policy,
64 const std::string& value,
66 : policy_(policy.DeepCopy()), value_(value), readonly_(readonly) {}
67 ~IndicatorTestCase() {}
69 const base::DictionaryValue& policy() const { return *policy_; }
71 const std::string& value() const { return value_; }
73 bool readonly() const { return readonly_; }
76 scoped_ptr<base::DictionaryValue> policy_;
80 DISALLOW_COPY_AND_ASSIGN(IndicatorTestCase);
83 // Contains the testing details for a single pref affected by a policy. This is
84 // part of the data loaded from chrome/test/data/policy/policy_test_cases.json.
87 PrefMapping(const std::string& pref,
89 const std::string& indicator_test_setup_js,
90 const std::string& indicator_selector)
92 is_local_state_(is_local_state),
93 indicator_test_setup_js_(indicator_test_setup_js),
94 indicator_selector_(indicator_selector) {
98 const std::string& pref() const { return pref_; }
100 bool is_local_state() const { return is_local_state_; }
102 const std::string& indicator_test_setup_js() const {
103 return indicator_test_setup_js_;
106 const std::string& indicator_selector() const {
107 return indicator_selector_;
110 const ScopedVector<IndicatorTestCase>& indicator_test_cases() const {
111 return indicator_test_cases_;
113 void AddIndicatorTestCase(IndicatorTestCase* test_case) {
114 indicator_test_cases_.push_back(test_case);
119 bool is_local_state_;
120 std::string indicator_test_setup_js_;
121 std::string indicator_selector_;
122 ScopedVector<IndicatorTestCase> indicator_test_cases_;
124 DISALLOW_COPY_AND_ASSIGN(PrefMapping);
127 // Contains the testing details for a single policy. This is part of the data
128 // loaded from chrome/test/data/policy/policy_test_cases.json.
129 class PolicyTestCase {
131 PolicyTestCase(const std::string& name,
132 bool is_official_only,
133 bool can_be_recommended,
134 const std::string& indicator_selector)
136 is_official_only_(is_official_only),
137 can_be_recommended_(can_be_recommended),
138 indicator_selector_(indicator_selector) {}
141 const std::string& name() const { return name_; }
143 bool is_official_only() const { return is_official_only_; }
145 bool can_be_recommended() const { return can_be_recommended_; }
147 bool IsOsSupported() const {
149 const std::string os("win");
150 #elif defined(OS_MACOSX)
151 const std::string os("mac");
152 #elif defined(OS_CHROMEOS)
153 const std::string os("chromeos");
154 #elif defined(OS_LINUX)
155 const std::string os("linux");
157 #error "Unknown platform"
159 return std::find(supported_os_.begin(), supported_os_.end(), os) !=
162 void AddSupportedOs(const std::string& os) { supported_os_.push_back(os); }
164 bool IsSupported() const {
165 #if !defined(OFFICIAL_BUILD)
166 if (is_official_only())
169 return IsOsSupported();
172 const base::DictionaryValue& test_policy() const { return test_policy_; }
173 void SetTestPolicy(const base::DictionaryValue& policy) {
174 test_policy_.Clear();
175 test_policy_.MergeDictionary(&policy);
178 const ScopedVector<PrefMapping>& pref_mappings() const {
179 return pref_mappings_;
181 void AddPrefMapping(PrefMapping* pref_mapping) {
182 pref_mappings_.push_back(pref_mapping);
185 const std::string& indicator_selector() const { return indicator_selector_; }
189 bool is_official_only_;
190 bool can_be_recommended_;
191 std::vector<std::string> supported_os_;
192 base::DictionaryValue test_policy_;
193 ScopedVector<PrefMapping> pref_mappings_;
194 std::string indicator_selector_;
196 DISALLOW_COPY_AND_ASSIGN(PolicyTestCase);
199 // Parses all policy test cases and makes then available in a map.
200 class PolicyTestCases {
202 typedef std::map<std::string, PolicyTestCase*> PolicyTestCaseMap;
203 typedef PolicyTestCaseMap::const_iterator iterator;
206 base::FilePath path = ui_test_utils::GetTestFilePath(
207 base::FilePath(FILE_PATH_LITERAL("policy")),
208 base::FilePath(FILE_PATH_LITERAL("policy_test_cases.json")));
210 if (!base::ReadFileToString(path, &json)) {
215 std::string error_string;
216 base::DictionaryValue* dict = NULL;
217 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
218 json, base::JSON_PARSE_RFC, &error_code, &error_string));
219 if (!value.get() || !value->GetAsDictionary(&dict)) {
220 ADD_FAILURE() << "Error parsing policy_test_cases.json: " << error_string;
223 Schema chrome_schema = Schema::Wrap(GetChromeSchemaData());
224 if (!chrome_schema.valid()) {
228 for (Schema::Iterator it = chrome_schema.GetPropertiesIterator();
229 !it.IsAtEnd(); it.Advance()) {
230 PolicyTestCase* policy_test_case = GetPolicyTestCase(dict, it.key());
231 if (policy_test_case)
232 policy_test_cases_[it.key()] = policy_test_case;
237 STLDeleteValues(&policy_test_cases_);
240 const PolicyTestCase* Get(const std::string& name) const {
241 const iterator it = policy_test_cases_.find(name);
242 return it == end() ? NULL : it->second;
245 const PolicyTestCaseMap& map() const { return policy_test_cases_; }
246 iterator begin() const { return policy_test_cases_.begin(); }
247 iterator end() const { return policy_test_cases_.end(); }
250 PolicyTestCase* GetPolicyTestCase(const base::DictionaryValue* tests,
251 const std::string& name) {
252 const base::DictionaryValue* policy_test_dict = NULL;
253 if (!tests->GetDictionary(name, &policy_test_dict))
255 bool is_official_only = false;
256 policy_test_dict->GetBoolean("official_only", &is_official_only);
257 bool can_be_recommended = false;
258 policy_test_dict->GetBoolean("can_be_recommended", &can_be_recommended);
259 std::string indicator_selector;
260 policy_test_dict->GetString("indicator_selector", &indicator_selector);
261 PolicyTestCase* policy_test_case = new PolicyTestCase(name,
265 const base::ListValue* os_list = NULL;
266 if (policy_test_dict->GetList("os", &os_list)) {
267 for (size_t i = 0; i < os_list->GetSize(); ++i) {
269 if (os_list->GetString(i, &os))
270 policy_test_case->AddSupportedOs(os);
273 const base::DictionaryValue* policy = NULL;
274 if (policy_test_dict->GetDictionary("test_policy", &policy))
275 policy_test_case->SetTestPolicy(*policy);
276 const base::ListValue* pref_mappings = NULL;
277 if (policy_test_dict->GetList("pref_mappings", &pref_mappings)) {
278 for (size_t i = 0; i < pref_mappings->GetSize(); ++i) {
279 const base::DictionaryValue* pref_mapping_dict = NULL;
281 if (!pref_mappings->GetDictionary(i, &pref_mapping_dict) ||
282 !pref_mapping_dict->GetString("pref", &pref)) {
283 ADD_FAILURE() << "Malformed pref_mappings entry in "
284 << "policy_test_cases.json.";
287 bool is_local_state = false;
288 pref_mapping_dict->GetBoolean("local_state", &is_local_state);
289 std::string indicator_test_setup_js;
290 pref_mapping_dict->GetString("indicator_test_setup_js",
291 &indicator_test_setup_js);
292 std::string indicator_selector;
293 pref_mapping_dict->GetString("indicator_selector", &indicator_selector);
294 PrefMapping* pref_mapping = new PrefMapping(
295 pref, is_local_state, indicator_test_setup_js, indicator_selector);
296 const base::ListValue* indicator_tests = NULL;
297 if (pref_mapping_dict->GetList("indicator_tests", &indicator_tests)) {
298 for (size_t i = 0; i < indicator_tests->GetSize(); ++i) {
299 const base::DictionaryValue* indicator_test_dict = NULL;
300 const base::DictionaryValue* policy = NULL;
301 if (!indicator_tests->GetDictionary(i, &indicator_test_dict) ||
302 !indicator_test_dict->GetDictionary("policy", &policy)) {
303 ADD_FAILURE() << "Malformed indicator_tests entry in "
304 << "policy_test_cases.json.";
308 indicator_test_dict->GetString("value", &value);
309 bool readonly = false;
310 indicator_test_dict->GetBoolean("readonly", &readonly);
311 pref_mapping->AddIndicatorTestCase(
312 new IndicatorTestCase(*policy, value, readonly));
315 policy_test_case->AddPrefMapping(pref_mapping);
318 return policy_test_case;
321 PolicyTestCaseMap policy_test_cases_;
323 DISALLOW_COPY_AND_ASSIGN(PolicyTestCases);
326 // Returns a pseudo-random integer distributed in [0, range).
327 int GetRandomNumber(int range) {
328 return rand() % range;
331 // Splits all known policies into subsets of the given |chunk_size|. The
332 // policies are shuffled so that there is no correlation between their initial
333 // alphabetic ordering and the assignment to chunks. This ensures that the
334 // expected number of policies with long-running test cases is equal for each
335 // subset. The shuffle algorithm uses a fixed seed, ensuring that no randomness
336 // is introduced into the testing process.
337 std::vector<std::vector<std::string> > SplitPoliciesIntoChunks(int chunk_size) {
338 Schema chrome_schema = Schema::Wrap(GetChromeSchemaData());
339 if (!chrome_schema.valid())
342 std::vector<std::string> policies;
343 for (Schema::Iterator it = chrome_schema.GetPropertiesIterator();
344 !it.IsAtEnd(); it.Advance()) {
345 policies.push_back(it.key());
348 // Use a fixed random seed to obtain a reproducible shuffle.
350 std::random_shuffle(policies.begin(), policies.end(), GetRandomNumber);
352 std::vector<std::vector<std::string> > chunks;
353 std::vector<std::string>::const_iterator it = policies.begin();
354 const std::vector<std::string>::const_iterator end = policies.end();
355 for ( ; end - it >= chunk_size; it += chunk_size)
356 chunks.push_back(std::vector<std::string>(it, it + chunk_size));
358 chunks.push_back(std::vector<std::string>(it, end));
362 void VerifyControlledSettingIndicators(Browser* browser,
363 const std::string& selector,
364 const std::string& value,
365 const std::string& controlled_by,
367 std::stringstream javascript;
368 javascript << "var nodes = document.querySelectorAll("
369 << " 'span.controlled-setting-indicator"
370 << selector.c_str() << "');"
371 << "var indicators = [];"
372 << "for (var i = 0; i < nodes.length; i++) {"
373 << " var node = nodes[i];"
374 << " var indicator = {};"
375 << " indicator.value = node.value || '';"
376 << " indicator.controlledBy = node.controlledBy || '';"
377 << " indicator.readOnly = node.readOnly || false;"
378 << " indicator.visible ="
379 << " window.getComputedStyle(node).display != 'none';"
380 << " indicators.push(indicator)"
382 << "domAutomationController.send(JSON.stringify(indicators));";
383 content::WebContents* contents =
384 browser->tab_strip_model()->GetActiveWebContents();
386 // Retrieve the state of all controlled setting indicators matching the
387 // |selector| as JSON.
388 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, javascript.str(),
390 scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json));
391 const base::ListValue* indicators = NULL;
392 ASSERT_TRUE(value_ptr.get());
393 ASSERT_TRUE(value_ptr->GetAsList(&indicators));
394 // Verify that controlled setting indicators representing |value| are visible
395 // and have the correct state while those not representing |value| are
397 if (!controlled_by.empty()) {
398 EXPECT_GT(indicators->GetSize(), 0u)
399 << "Expected to find at least one controlled setting indicator.";
401 bool have_visible_indicators = false;
402 for (base::ListValue::const_iterator indicator = indicators->begin();
403 indicator != indicators->end(); ++indicator) {
404 const base::DictionaryValue* properties = NULL;
405 ASSERT_TRUE((*indicator)->GetAsDictionary(&properties));
406 std::string indicator_value;
407 std::string indicator_controlled_by;
408 bool indicator_readonly;
409 bool indicator_visible;
410 EXPECT_TRUE(properties->GetString("value", &indicator_value));
411 EXPECT_TRUE(properties->GetString("controlledBy",
412 &indicator_controlled_by));
413 EXPECT_TRUE(properties->GetBoolean("readOnly", &indicator_readonly));
414 EXPECT_TRUE(properties->GetBoolean("visible", &indicator_visible));
415 if (!controlled_by.empty() && (indicator_value == value)) {
416 EXPECT_EQ(controlled_by, indicator_controlled_by);
417 EXPECT_EQ(readonly, indicator_readonly);
418 EXPECT_TRUE(indicator_visible);
419 have_visible_indicators = true;
421 EXPECT_FALSE(indicator_visible);
424 if (!controlled_by.empty()) {
425 EXPECT_TRUE(have_visible_indicators)
426 << "Expected to find at least one visible controlled setting "
433 TEST(PolicyPrefsTestCoverageTest, AllPoliciesHaveATestCase) {
434 // Verifies that all known policies have a test case in the JSON file.
435 // This test fails when a policy is added to
436 // components/policy/resources/policy_templates.json but a test case is not
437 // added to chrome/test/data/policy/policy_test_cases.json.
438 Schema chrome_schema = Schema::Wrap(GetChromeSchemaData());
439 ASSERT_TRUE(chrome_schema.valid());
441 PolicyTestCases policy_test_cases;
442 for (Schema::Iterator it = chrome_schema.GetPropertiesIterator();
443 !it.IsAtEnd(); it.Advance()) {
444 EXPECT_TRUE(ContainsKey(policy_test_cases.map(), it.key()))
445 << "Missing policy test case for: " << it.key();
449 // Base class for tests that change policy.
450 class PolicyPrefsTest : public InProcessBrowserTest {
452 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
453 EXPECT_CALL(provider_, IsInitializationComplete(_))
454 .WillRepeatedly(Return(true));
455 BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_);
458 virtual void SetUpOnMainThread() OVERRIDE {
459 ui_test_utils::WaitForTemplateURLServiceToLoad(
460 TemplateURLServiceFactory::GetForProfile(browser()->profile()));
463 virtual void TearDownOnMainThread() OVERRIDE {
464 ClearProviderPolicy();
467 void ClearProviderPolicy() {
468 provider_.UpdateChromePolicy(PolicyMap());
469 base::RunLoop().RunUntilIdle();
472 void SetProviderPolicy(const base::DictionaryValue& policies,
474 PolicyMap policy_map;
475 for (base::DictionaryValue::Iterator it(policies);
476 !it.IsAtEnd(); it.Advance()) {
477 const PolicyDetails* policy_details = GetChromePolicyDetails(it.key());
478 ASSERT_TRUE(policy_details);
483 it.value().DeepCopy(),
484 policy_details->max_external_data_size ?
485 new ExternalDataFetcher(base::WeakPtr<ExternalDataManager>(),
489 provider_.UpdateChromePolicy(policy_map);
490 base::RunLoop().RunUntilIdle();
493 MockConfigurationPolicyProvider provider_;
496 // Verifies that policies make their corresponding preferences become managed,
497 // and that the user can't override that setting.
498 IN_PROC_BROWSER_TEST_F(PolicyPrefsTest, PolicyToPrefsMapping) {
499 PrefService* local_state = g_browser_process->local_state();
500 PrefService* user_prefs = browser()->profile()->GetPrefs();
502 const PolicyTestCases test_cases;
503 for (PolicyTestCases::iterator it = test_cases.begin();
504 it != test_cases.end(); ++it) {
505 const ScopedVector<PrefMapping>& pref_mappings =
506 it->second->pref_mappings();
507 if (!it->second->IsSupported() || pref_mappings.empty())
510 LOG(INFO) << "Testing policy: " << it->first;
512 for (ScopedVector<PrefMapping>::const_iterator
513 pref_mapping = pref_mappings.begin();
514 pref_mapping != pref_mappings.end();
516 // Skip Chrome OS preferences that use a different backend and cannot be
517 // retrieved through the prefs mechanism.
518 if (StartsWithASCII((*pref_mapping)->pref(), kCrosSettingsPrefix, true))
521 PrefService* prefs = (*pref_mapping)->is_local_state() ?
522 local_state : user_prefs;
523 // The preference must have been registered.
524 const PrefService::Preference* pref =
525 prefs->FindPreference((*pref_mapping)->pref().c_str());
528 // Verify that setting the policy overrides the pref.
529 ClearProviderPolicy();
530 prefs->ClearPref((*pref_mapping)->pref().c_str());
531 EXPECT_TRUE(pref->IsDefaultValue());
532 EXPECT_TRUE(pref->IsUserModifiable());
533 EXPECT_FALSE(pref->IsUserControlled());
534 EXPECT_FALSE(pref->IsManaged());
536 SetProviderPolicy(it->second->test_policy(), POLICY_LEVEL_MANDATORY);
537 EXPECT_FALSE(pref->IsDefaultValue());
538 EXPECT_FALSE(pref->IsUserModifiable());
539 EXPECT_FALSE(pref->IsUserControlled());
540 EXPECT_TRUE(pref->IsManaged());
545 class PolicyPrefIndicatorTest
546 : public PolicyPrefsTest,
547 public testing::WithParamInterface<std::vector<std::string> > {
550 // Verifies that controlled setting indicators correctly show whether a pref's
551 // value is recommended or enforced by a corresponding policy.
552 IN_PROC_BROWSER_TEST_P(PolicyPrefIndicatorTest, CheckPolicyIndicators) {
553 const PolicyTestCases test_cases;
554 PrefService* local_state = g_browser_process->local_state();
555 PrefService* user_prefs = browser()->profile()->GetPrefs();
557 ui_test_utils::NavigateToURL(browser(), GURL(kMainSettingsPage));
559 for (std::vector<std::string>::const_iterator it = GetParam().begin();
560 it != GetParam().end(); ++it) {
561 const PolicyTestCase* policy_test_case = test_cases.Get(*it);
562 ASSERT_TRUE(policy_test_case) << "PolicyTestCase not found for " << *it;
563 if (!policy_test_case->IsSupported())
565 const ScopedVector<PrefMapping>& pref_mappings =
566 policy_test_case->pref_mappings();
567 if (policy_test_case->indicator_selector().empty()) {
568 bool has_pref_indicator_tests = false;
569 for (ScopedVector<PrefMapping>::const_iterator
570 pref_mapping = pref_mappings.begin();
571 pref_mapping != pref_mappings.end();
573 if (!(*pref_mapping)->indicator_test_cases().empty()) {
574 has_pref_indicator_tests = true;
578 if (!has_pref_indicator_tests)
582 LOG(INFO) << "Testing policy: " << *it;
584 if (!policy_test_case->indicator_selector().empty()) {
585 // Check that no controlled setting indicator is visible when no value is
587 ClearProviderPolicy();
588 VerifyControlledSettingIndicators(browser(),
589 policy_test_case->indicator_selector(),
593 // Check that the appropriate controlled setting indicator is shown when a
594 // value is enforced by policy.
595 SetProviderPolicy(policy_test_case->test_policy(),
596 POLICY_LEVEL_MANDATORY);
597 VerifyControlledSettingIndicators(browser(),
598 policy_test_case->indicator_selector(),
604 for (ScopedVector<PrefMapping>::const_iterator
605 pref_mapping = pref_mappings.begin();
606 pref_mapping != pref_mappings.end();
608 const ScopedVector<IndicatorTestCase>&
609 indicator_test_cases = (*pref_mapping)->indicator_test_cases();
610 if (indicator_test_cases.empty())
613 if (!(*pref_mapping)->indicator_test_setup_js().empty()) {
614 ASSERT_TRUE(content::ExecuteScript(
615 browser()->tab_strip_model()->GetActiveWebContents(),
616 (*pref_mapping)->indicator_test_setup_js()));
619 std::string indicator_selector = (*pref_mapping)->indicator_selector();
620 if (indicator_selector.empty())
621 indicator_selector = "[pref=\"" + (*pref_mapping)->pref() + "\"]";
622 for (ScopedVector<IndicatorTestCase>::const_iterator
623 indicator_test_case = indicator_test_cases.begin();
624 indicator_test_case != indicator_test_cases.end();
625 ++indicator_test_case) {
626 // Check that no controlled setting indicator is visible when no value
628 ClearProviderPolicy();
629 VerifyControlledSettingIndicators(
630 browser(), indicator_selector, std::string(), std::string(), false);
631 // Check that the appropriate controlled setting indicator is shown when
632 // a value is enforced by policy.
633 SetProviderPolicy((*indicator_test_case)->policy(),
634 POLICY_LEVEL_MANDATORY);
635 VerifyControlledSettingIndicators(browser(), indicator_selector,
636 (*indicator_test_case)->value(),
638 (*indicator_test_case)->readonly());
640 if (!policy_test_case->can_be_recommended())
643 PrefService* prefs = (*pref_mapping)->is_local_state() ?
644 local_state : user_prefs;
645 // The preference must have been registered.
646 const PrefService::Preference* pref =
647 prefs->FindPreference((*pref_mapping)->pref().c_str());
650 // Check that the appropriate controlled setting indicator is shown when
651 // a value is recommended by policy and the user has not overridden the
653 SetProviderPolicy((*indicator_test_case)->policy(),
654 POLICY_LEVEL_RECOMMENDED);
655 VerifyControlledSettingIndicators(browser(), indicator_selector,
656 (*indicator_test_case)->value(),
658 (*indicator_test_case)->readonly());
659 // Check that the appropriate controlled setting indicator is shown when
660 // a value is recommended by policy and the user has overridden the
662 prefs->Set((*pref_mapping)->pref().c_str(), *pref->GetValue());
663 VerifyControlledSettingIndicators(browser(), indicator_selector,
664 (*indicator_test_case)->value(),
666 (*indicator_test_case)->readonly());
667 prefs->ClearPref((*pref_mapping)->pref().c_str());
673 INSTANTIATE_TEST_CASE_P(PolicyPrefIndicatorTestInstance,
674 PolicyPrefIndicatorTest,
675 testing::ValuesIn(SplitPoliciesIntoChunks(50)));
677 } // namespace policy