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 <algorithm> 6 #include <map> 7 #include <sstream> 8 #include <string> 9 #include <vector> 10 11 #include "base/basictypes.h" 12 #include "base/file_util.h" 13 #include "base/files/file_path.h" 14 #include "base/json/json_reader.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/memory/scoped_vector.h" 17 #include "base/prefs/pref_service.h" 18 #include "base/run_loop.h" 19 #include "base/stl_util.h" 20 #include "base/strings/string_util.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "base/values.h" 23 #include "chrome/browser/browser_process.h" 24 #include "chrome/browser/policy/browser_policy_connector.h" 25 #include "chrome/browser/policy/mock_configuration_policy_provider.h" 26 #include "chrome/browser/policy/policy_map.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 "content/public/browser/web_contents.h" 34 #include "content/public/test/browser_test_utils.h" 35 #include "policy/policy_constants.h" 36 #include "testing/gmock/include/gmock/gmock.h" 37 #include "testing/gtest/include/gtest/gtest.h" 38 #include "url/gurl.h" 39 40 using testing::AnyNumber; 41 using testing::Return; 42 using testing::_; 43 44 namespace policy { 45 46 namespace { 47 48 const char kMainSettingsPage[] = "chrome://settings-frame"; 49 50 const char kCrosSettingsPrefix[] = "cros."; 51 52 // Contains the details of a single test case verifying that the controlled 53 // setting indicators for a pref affected by a policy work correctly. This is 54 // part of the data loaded from chrome/test/data/policy/policy_test_cases.json. 55 class IndicatorTestCase { 56 public: 57 IndicatorTestCase(const base::DictionaryValue& policy, 58 const std::string& value, 59 bool readonly) 60 : policy_(policy.DeepCopy()), value_(value), readonly_(readonly) {} 61 ~IndicatorTestCase() {} 62 63 const base::DictionaryValue& policy() const { return *policy_; } 64 65 const std::string& value() const { return value_; } 66 67 bool readonly() const { return readonly_; } 68 69 private: 70 scoped_ptr<base::DictionaryValue> policy_; 71 std::string value_; 72 bool readonly_; 73 74 DISALLOW_COPY_AND_ASSIGN(IndicatorTestCase); 75 }; 76 77 // Contains the testing details for a single pref affected by a policy. This is 78 // part of the data loaded from chrome/test/data/policy/policy_test_cases.json. 79 class PrefMapping { 80 public: 81 PrefMapping(const std::string& pref, 82 bool is_local_state, 83 const std::string& indicator_test_setup_js, 84 const std::string& indicator_selector) 85 : pref_(pref), 86 is_local_state_(is_local_state), 87 indicator_test_setup_js_(indicator_test_setup_js), 88 indicator_selector_(indicator_selector) { 89 } 90 ~PrefMapping() {} 91 92 const std::string& pref() const { return pref_; } 93 94 bool is_local_state() const { return is_local_state_; } 95 96 const std::string& indicator_test_setup_js() const { 97 return indicator_test_setup_js_; 98 } 99 100 const std::string& indicator_selector() const { 101 return indicator_selector_; 102 } 103 104 const ScopedVector<IndicatorTestCase>& indicator_test_cases() const { 105 return indicator_test_cases_; 106 } 107 void AddIndicatorTestCase(IndicatorTestCase* test_case) { 108 indicator_test_cases_.push_back(test_case); 109 } 110 111 private: 112 std::string pref_; 113 bool is_local_state_; 114 std::string indicator_test_setup_js_; 115 std::string indicator_selector_; 116 ScopedVector<IndicatorTestCase> indicator_test_cases_; 117 118 DISALLOW_COPY_AND_ASSIGN(PrefMapping); 119 }; 120 121 // Contains the testing details for a single policy. This is part of the data 122 // loaded from chrome/test/data/policy/policy_test_cases.json. 123 class PolicyTestCase { 124 public: 125 PolicyTestCase(const std::string& name, 126 bool is_official_only, 127 bool can_be_recommended) 128 : name_(name), 129 is_official_only_(is_official_only), 130 can_be_recommended_(can_be_recommended) {} 131 ~PolicyTestCase() {} 132 133 const std::string& name() const { return name_; } 134 135 bool is_official_only() const { return is_official_only_; } 136 137 bool can_be_recommended() const { return can_be_recommended_; } 138 139 bool IsOsSupported() const { 140 #if defined(OS_WIN) 141 const std::string os("win"); 142 #elif defined(OS_MACOSX) 143 const std::string os("mac"); 144 #elif defined(OS_CHROMEOS) 145 const std::string os("chromeos"); 146 #elif defined(OS_LINUX) 147 const std::string os("linux"); 148 #else 149 #error "Unknown platform" 150 #endif 151 return std::find(supported_os_.begin(), supported_os_.end(), os) != 152 supported_os_.end(); 153 } 154 void AddSupportedOs(const std::string& os) { supported_os_.push_back(os); } 155 156 bool IsSupported() const { 157 #if !defined(OFFICIAL_BUILD) 158 if (is_official_only()) 159 return false; 160 #endif 161 return IsOsSupported(); 162 } 163 164 const PolicyMap& test_policy() const { return test_policy_; } 165 void SetTestPolicy(const PolicyMap& policy) { 166 test_policy_.CopyFrom(policy); 167 } 168 169 const ScopedVector<PrefMapping>& pref_mappings() const { 170 return pref_mappings_; 171 } 172 void AddPrefMapping(PrefMapping* pref_mapping) { 173 pref_mappings_.push_back(pref_mapping); 174 } 175 176 private: 177 std::string name_; 178 bool is_official_only_; 179 bool can_be_recommended_; 180 std::vector<std::string> supported_os_; 181 PolicyMap test_policy_; 182 ScopedVector<PrefMapping> pref_mappings_; 183 184 DISALLOW_COPY_AND_ASSIGN(PolicyTestCase); 185 }; 186 187 // Parses all policy test cases and makes then available in a map. 188 class PolicyTestCases { 189 public: 190 typedef std::map<std::string, PolicyTestCase*> PolicyTestCaseMap; 191 typedef PolicyTestCaseMap::const_iterator iterator; 192 193 PolicyTestCases() { 194 policy_test_cases_ = new std::map<std::string, PolicyTestCase*>(); 195 196 base::FilePath path = ui_test_utils::GetTestFilePath( 197 base::FilePath(FILE_PATH_LITERAL("policy")), 198 base::FilePath(FILE_PATH_LITERAL("policy_test_cases.json"))); 199 std::string json; 200 if (!file_util::ReadFileToString(path, &json)) { 201 ADD_FAILURE(); 202 return; 203 } 204 int error_code = -1; 205 std::string error_string; 206 base::DictionaryValue* dict = NULL; 207 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( 208 json, base::JSON_PARSE_RFC, &error_code, &error_string)); 209 if (!value.get() || !value->GetAsDictionary(&dict)) { 210 ADD_FAILURE() << "Error parsing policy_test_cases.json: " << error_string; 211 return; 212 } 213 const PolicyDefinitionList* list = GetChromePolicyDefinitionList(); 214 for (const PolicyDefinitionList::Entry* policy = list->begin; 215 policy != list->end; ++policy) { 216 PolicyTestCase* policy_test_case = GetPolicyTestCase(dict, policy->name); 217 if (policy_test_case) 218 (*policy_test_cases_)[policy->name] = policy_test_case; 219 } 220 } 221 222 ~PolicyTestCases() { 223 STLDeleteValues(policy_test_cases_); 224 delete policy_test_cases_; 225 } 226 227 const PolicyTestCase* Get(const std::string& name) { 228 iterator it = policy_test_cases_->find(name); 229 return it == end() ? NULL : it->second; 230 } 231 232 const PolicyTestCaseMap& map() const { return *policy_test_cases_; } 233 iterator begin() const { return policy_test_cases_->begin(); } 234 iterator end() const { return policy_test_cases_->end(); } 235 236 private: 237 PolicyTestCase* GetPolicyTestCase(const base::DictionaryValue* tests, 238 const std::string& name) { 239 const base::DictionaryValue* policy_test_dict = NULL; 240 if (!tests->GetDictionary(name, &policy_test_dict)) 241 return NULL; 242 bool is_official_only = false; 243 policy_test_dict->GetBoolean("official_only", &is_official_only); 244 bool can_be_recommended = false; 245 policy_test_dict->GetBoolean("can_be_recommended", &can_be_recommended); 246 PolicyTestCase* policy_test_case = 247 new PolicyTestCase(name, is_official_only, can_be_recommended); 248 const base::ListValue* os_list = NULL; 249 if (policy_test_dict->GetList("os", &os_list)) { 250 for (size_t i = 0; i < os_list->GetSize(); ++i) { 251 std::string os; 252 if (os_list->GetString(i, &os)) 253 policy_test_case->AddSupportedOs(os); 254 } 255 } 256 const base::DictionaryValue* policy_dict = NULL; 257 if (policy_test_dict->GetDictionary("test_policy", &policy_dict)) { 258 PolicyMap policy; 259 policy.LoadFrom(policy_dict, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); 260 policy_test_case->SetTestPolicy(policy); 261 } 262 const base::ListValue* pref_mappings = NULL; 263 if (policy_test_dict->GetList("pref_mappings", &pref_mappings)) { 264 for (size_t i = 0; i < pref_mappings->GetSize(); ++i) { 265 const base::DictionaryValue* pref_mapping_dict = NULL; 266 std::string pref; 267 if (!pref_mappings->GetDictionary(i, &pref_mapping_dict) || 268 !pref_mapping_dict->GetString("pref", &pref)) { 269 ADD_FAILURE() << "Malformed pref_mappings entry in " 270 << "policy_test_cases.json."; 271 continue; 272 } 273 bool is_local_state = false; 274 pref_mapping_dict->GetBoolean("local_state", &is_local_state); 275 std::string indicator_test_setup_js; 276 pref_mapping_dict->GetString("indicator_test_setup_js", 277 &indicator_test_setup_js); 278 std::string indicator_selector; 279 pref_mapping_dict->GetString("indicator_selector", &indicator_selector); 280 PrefMapping* pref_mapping = new PrefMapping( 281 pref, is_local_state, indicator_test_setup_js, indicator_selector); 282 const base::ListValue* indicator_tests = NULL; 283 if (pref_mapping_dict->GetList("indicator_tests", &indicator_tests)) { 284 for (size_t i = 0; i < indicator_tests->GetSize(); ++i) { 285 const base::DictionaryValue* indicator_test_dict = NULL; 286 const base::DictionaryValue* policy = NULL; 287 if (!indicator_tests->GetDictionary(i, &indicator_test_dict) || 288 !indicator_test_dict->GetDictionary("policy", &policy)) { 289 ADD_FAILURE() << "Malformed indicator_tests entry in " 290 << "policy_test_cases.json."; 291 continue; 292 } 293 std::string value; 294 indicator_test_dict->GetString("value", &value); 295 bool readonly = false; 296 indicator_test_dict->GetBoolean("readonly", &readonly); 297 pref_mapping->AddIndicatorTestCase( 298 new IndicatorTestCase(*policy, value, readonly)); 299 } 300 } 301 policy_test_case->AddPrefMapping(pref_mapping); 302 } 303 } 304 return policy_test_case; 305 } 306 307 PolicyTestCaseMap* policy_test_cases_; 308 309 DISALLOW_COPY_AND_ASSIGN(PolicyTestCases); 310 }; 311 312 void VerifyControlledSettingIndicators(Browser* browser, 313 const std::string& selector, 314 const std::string& value, 315 const std::string& controlled_by, 316 bool readonly) { 317 std::stringstream javascript; 318 javascript << "var nodes = document.querySelectorAll(" 319 << " 'span.controlled-setting-indicator" 320 << selector.c_str() << "');" 321 << "var indicators = [];" 322 << "for (var i = 0; i < nodes.length; i++) {" 323 << " var node = nodes[i];" 324 << " var indicator = {};" 325 << " indicator.value = node.value || '';" 326 << " indicator.controlledBy = node.controlledBy || '';" 327 << " indicator.readOnly = node.readOnly || false;" 328 << " indicator.visible =" 329 << " window.getComputedStyle(node).display != 'none';" 330 << " indicators.push(indicator)" 331 << "}" 332 << "domAutomationController.send(JSON.stringify(indicators));"; 333 content::WebContents* contents = 334 browser->tab_strip_model()->GetActiveWebContents(); 335 std::string json; 336 // Retrieve the state of all controlled setting indicators matching the 337 // |selector| as JSON. 338 ASSERT_TRUE(content::ExecuteScriptAndExtractString(contents, javascript.str(), 339 &json)); 340 scoped_ptr<base::Value> value_ptr(base::JSONReader::Read(json)); 341 const base::ListValue* indicators = NULL; 342 ASSERT_TRUE(value_ptr.get()); 343 ASSERT_TRUE(value_ptr->GetAsList(&indicators)); 344 // Verify that controlled setting indicators representing |value| are visible 345 // and have the correct state while those not representing |value| are 346 // invisible. 347 if (!controlled_by.empty()) { 348 EXPECT_GT(indicators->GetSize(), 0u) 349 << "Expected to find at least one controlled setting indicator."; 350 } 351 bool have_visible_indicators = false; 352 for (base::ListValue::const_iterator indicator = indicators->begin(); 353 indicator != indicators->end(); ++indicator) { 354 const base::DictionaryValue* properties = NULL; 355 ASSERT_TRUE((*indicator)->GetAsDictionary(&properties)); 356 std::string indicator_value; 357 std::string indicator_controlled_by; 358 bool indicator_readonly; 359 bool indicator_visible; 360 EXPECT_TRUE(properties->GetString("value", &indicator_value)); 361 EXPECT_TRUE(properties->GetString("controlledBy", 362 &indicator_controlled_by)); 363 EXPECT_TRUE(properties->GetBoolean("readOnly", &indicator_readonly)); 364 EXPECT_TRUE(properties->GetBoolean("visible", &indicator_visible)); 365 if (!controlled_by.empty() && (indicator_value == value)) { 366 EXPECT_EQ(controlled_by, indicator_controlled_by); 367 EXPECT_EQ(readonly, indicator_readonly); 368 EXPECT_TRUE(indicator_visible); 369 have_visible_indicators = true; 370 } else { 371 EXPECT_FALSE(indicator_visible); 372 } 373 } 374 if (!controlled_by.empty()) { 375 EXPECT_TRUE(have_visible_indicators) 376 << "Expected to find at least one visible controlled setting " 377 << "indicator."; 378 } 379 } 380 381 } // namespace 382 383 // Base class for tests that change policy and are parameterized with a policy 384 // definition. 385 class PolicyPrefsTest 386 : public InProcessBrowserTest, 387 public testing::WithParamInterface<PolicyDefinitionList::Entry> { 388 protected: 389 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 390 EXPECT_CALL(provider_, IsInitializationComplete(_)) 391 .WillRepeatedly(Return(true)); 392 EXPECT_CALL(provider_, RegisterPolicyDomain(_)).Times(AnyNumber()); 393 BrowserPolicyConnector::SetPolicyProviderForTesting(&provider_); 394 } 395 396 virtual void SetUpOnMainThread() OVERRIDE { 397 ui_test_utils::WaitForTemplateURLServiceToLoad( 398 TemplateURLServiceFactory::GetForProfile(browser()->profile())); 399 } 400 401 void UpdateProviderPolicy(const PolicyMap& policy) { 402 provider_.UpdateChromePolicy(policy); 403 base::RunLoop loop; 404 loop.RunUntilIdle(); 405 } 406 407 PolicyTestCases policy_test_cases_; 408 MockConfigurationPolicyProvider provider_; 409 }; 410 411 TEST(PolicyPrefsTestCoverageTest, AllPoliciesHaveATestCase) { 412 // Verifies that all known policies have a test case in the JSON file. 413 // This test fails when a policy is added to 414 // chrome/app/policy/policy_templates.json but a test case is not added to 415 // chrome/test/data/policy/policy_test_cases.json. 416 PolicyTestCases policy_test_cases; 417 const PolicyDefinitionList* list = GetChromePolicyDefinitionList(); 418 for (const PolicyDefinitionList::Entry* policy = list->begin; 419 policy != list->end; ++policy) { 420 EXPECT_TRUE(ContainsKey(policy_test_cases.map(), policy->name)) 421 << "Missing policy test case for: " << policy->name; 422 } 423 } 424 425 IN_PROC_BROWSER_TEST_P(PolicyPrefsTest, PolicyToPrefsMapping) { 426 // Verifies that policies make their corresponding preferences become managed, 427 // and that the user can't override that setting. 428 const PolicyTestCase* test_case = policy_test_cases_.Get(GetParam().name); 429 ASSERT_TRUE(test_case) << "PolicyTestCase not found for " << GetParam().name; 430 const ScopedVector<PrefMapping>& pref_mappings = test_case->pref_mappings(); 431 if (!test_case->IsSupported() || pref_mappings.empty()) 432 return; 433 LOG(INFO) << "Testing policy: " << test_case->name(); 434 435 for (ScopedVector<PrefMapping>::const_iterator 436 pref_mapping = pref_mappings.begin(); 437 pref_mapping != pref_mappings.end(); 438 ++pref_mapping) { 439 // Skip Chrome OS preferences that use a different backend and cannot be 440 // retrieved through the prefs mechanism. 441 if (StartsWithASCII((*pref_mapping)->pref(), kCrosSettingsPrefix, true)) 442 continue; 443 444 PrefService* local_state = g_browser_process->local_state(); 445 PrefService* user_prefs = browser()->profile()->GetPrefs(); 446 PrefService* prefs = (*pref_mapping)->is_local_state() ? 447 local_state : user_prefs; 448 // The preference must have been registered. 449 const PrefService::Preference* pref = 450 prefs->FindPreference((*pref_mapping)->pref().c_str()); 451 ASSERT_TRUE(pref); 452 prefs->ClearPref((*pref_mapping)->pref().c_str()); 453 454 // Verify that setting the policy overrides the pref. 455 const PolicyMap kNoPolicies; 456 UpdateProviderPolicy(kNoPolicies); 457 EXPECT_TRUE(pref->IsDefaultValue()); 458 EXPECT_TRUE(pref->IsUserModifiable()); 459 EXPECT_FALSE(pref->IsUserControlled()); 460 EXPECT_FALSE(pref->IsManaged()); 461 462 UpdateProviderPolicy(test_case->test_policy()); 463 EXPECT_FALSE(pref->IsDefaultValue()); 464 EXPECT_FALSE(pref->IsUserModifiable()); 465 EXPECT_FALSE(pref->IsUserControlled()); 466 EXPECT_TRUE(pref->IsManaged()); 467 } 468 } 469 470 IN_PROC_BROWSER_TEST_P(PolicyPrefsTest, CheckPolicyIndicators) { 471 // Verifies that controlled setting indicators correctly show whether a pref's 472 // value is recommended or enforced by a corresponding policy. 473 const PolicyTestCase* policy_test_case = 474 policy_test_cases_.Get(GetParam().name); 475 ASSERT_TRUE(policy_test_case) << "PolicyTestCase not found for " 476 << GetParam().name; 477 const ScopedVector<PrefMapping>& pref_mappings = 478 policy_test_case->pref_mappings(); 479 if (!policy_test_case->IsSupported() || pref_mappings.empty()) 480 return; 481 bool has_indicator_tests = false; 482 for (ScopedVector<PrefMapping>::const_iterator 483 pref_mapping = pref_mappings.begin(); 484 pref_mapping != pref_mappings.end(); 485 ++pref_mapping) { 486 if (!(*pref_mapping)->indicator_test_cases().empty()) { 487 has_indicator_tests = true; 488 break; 489 } 490 } 491 if (!has_indicator_tests) 492 return; 493 LOG(INFO) << "Testing policy: " << policy_test_case->name(); 494 495 for (ScopedVector<PrefMapping>::const_iterator 496 pref_mapping = pref_mappings.begin(); 497 pref_mapping != pref_mappings.end(); 498 ++pref_mapping) { 499 const ScopedVector<IndicatorTestCase>& 500 indicator_test_cases = (*pref_mapping)->indicator_test_cases(); 501 if (indicator_test_cases.empty()) 502 continue; 503 504 ui_test_utils::NavigateToURL(browser(), GURL(kMainSettingsPage)); 505 if (!(*pref_mapping)->indicator_test_setup_js().empty()) { 506 ASSERT_TRUE(content::ExecuteScript( 507 browser()->tab_strip_model()->GetActiveWebContents(), 508 (*pref_mapping)->indicator_test_setup_js())); 509 } 510 511 std::string indicator_selector = (*pref_mapping)->indicator_selector(); 512 if (indicator_selector.empty()) 513 indicator_selector = "[pref=\"" + (*pref_mapping)->pref() + "\"]"; 514 for (ScopedVector<IndicatorTestCase>::const_iterator 515 indicator_test_case = indicator_test_cases.begin(); 516 indicator_test_case != indicator_test_cases.end(); 517 ++indicator_test_case) { 518 // Check that no controlled setting indicator is visible when no value is 519 // set by policy. 520 PolicyMap policies; 521 UpdateProviderPolicy(policies); 522 VerifyControlledSettingIndicators( 523 browser(), indicator_selector, std::string(), std::string(), false); 524 // Check that the appropriate controlled setting indicator is shown when a 525 // value is enforced by policy. 526 policies.LoadFrom(&(*indicator_test_case)->policy(), 527 POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER); 528 UpdateProviderPolicy(policies); 529 VerifyControlledSettingIndicators(browser(), indicator_selector, 530 (*indicator_test_case)->value(), 531 "policy", 532 (*indicator_test_case)->readonly()); 533 534 if (!policy_test_case->can_be_recommended()) 535 continue; 536 537 PrefService* local_state = g_browser_process->local_state(); 538 PrefService* user_prefs = browser()->profile()->GetPrefs(); 539 PrefService* prefs = (*pref_mapping)->is_local_state() ? 540 local_state : user_prefs; 541 // The preference must have been registered. 542 const PrefService::Preference* pref = 543 prefs->FindPreference((*pref_mapping)->pref().c_str()); 544 ASSERT_TRUE(pref); 545 546 // Check that the appropriate controlled setting indicator is shown when a 547 // value is recommended by policy and the user has not overridden the 548 // recommendation. 549 policies.LoadFrom(&(*indicator_test_case)->policy(), 550 POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER); 551 UpdateProviderPolicy(policies); 552 VerifyControlledSettingIndicators(browser(), indicator_selector, 553 (*indicator_test_case)->value(), 554 "recommended", 555 (*indicator_test_case)->readonly()); 556 // Check that the appropriate controlled setting indicator is shown when a 557 // value is recommended by policy and the user has overriddent the 558 // recommendation. 559 prefs->Set((*pref_mapping)->pref().c_str(), *pref->GetValue()); 560 VerifyControlledSettingIndicators(browser(), indicator_selector, 561 (*indicator_test_case)->value(), 562 "hasRecommendation", 563 (*indicator_test_case)->readonly()); 564 prefs->ClearPref((*pref_mapping)->pref().c_str()); 565 } 566 } 567 } 568 569 INSTANTIATE_TEST_CASE_P( 570 PolicyPrefsTestInstance, 571 PolicyPrefsTest, 572 testing::ValuesIn(GetChromePolicyDefinitionList()->begin, 573 GetChromePolicyDefinitionList()->end)); 574 575 } // namespace policy 576