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
40using testing::AnyNumber;
41using testing::Return;
42using testing::_;
43
44namespace policy {
45
46namespace {
47
48const char kMainSettingsPage[] = "chrome://settings-frame";
49
50const 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.
55class 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.
79class 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.
123class 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.
188class 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
312void 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.
385class 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
411TEST(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
425IN_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
470IN_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
569INSTANTIATE_TEST_CASE_P(
570    PolicyPrefsTestInstance,
571    PolicyPrefsTest,
572    testing::ValuesIn(GetChromePolicyDefinitionList()->begin,
573                      GetChromePolicyDefinitionList()->end));
574
575}  // namespace policy
576