Home | History | Annotate | Download | only in policy
      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 <CoreFoundation/CoreFoundation.h>
      6 
      7 #include "base/basictypes.h"
      8 #include "base/callback.h"
      9 #include "base/mac/scoped_cftyperef.h"
     10 #include "base/strings/sys_string_conversions.h"
     11 #include "base/values.h"
     12 #include "chrome/browser/policy/async_policy_provider.h"
     13 #include "chrome/browser/policy/configuration_policy_provider_test.h"
     14 #include "chrome/browser/policy/external_data_fetcher.h"
     15 #include "chrome/browser/policy/policy_bundle.h"
     16 #include "chrome/browser/policy/policy_loader_mac.h"
     17 #include "chrome/browser/policy/policy_map.h"
     18 #include "chrome/browser/policy/preferences_mock_mac.h"
     19 #include "policy/policy_constants.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 using base::ScopedCFTypeRef;
     23 
     24 namespace policy {
     25 
     26 namespace {
     27 
     28 // Converts a base::Value to the equivalent CFPropertyListRef.
     29 // The returned value is owned by the caller.
     30 CFPropertyListRef CreatePropertyFromValue(const base::Value* value) {
     31   switch (value->GetType()) {
     32     case base::Value::TYPE_NULL:
     33       return kCFNull;
     34 
     35     case base::Value::TYPE_BOOLEAN: {
     36       bool bool_value;
     37       if (value->GetAsBoolean(&bool_value))
     38         return bool_value ? kCFBooleanTrue : kCFBooleanFalse;
     39       break;
     40     }
     41 
     42     case base::Value::TYPE_INTEGER: {
     43       int int_value;
     44       if (value->GetAsInteger(&int_value)) {
     45         return CFNumberCreate(
     46             kCFAllocatorDefault, kCFNumberIntType, &int_value);
     47       }
     48       break;
     49     }
     50 
     51     case base::Value::TYPE_DOUBLE: {
     52       double double_value;
     53       if (value->GetAsDouble(&double_value)) {
     54         return CFNumberCreate(
     55             kCFAllocatorDefault, kCFNumberDoubleType, &double_value);
     56       }
     57       break;
     58     }
     59 
     60     case base::Value::TYPE_STRING: {
     61       std::string string_value;
     62       if (value->GetAsString(&string_value))
     63         return base::SysUTF8ToCFStringRef(string_value);
     64       break;
     65     }
     66 
     67     case base::Value::TYPE_DICTIONARY: {
     68       const base::DictionaryValue* dict_value;
     69       if (value->GetAsDictionary(&dict_value)) {
     70         // |dict| is owned by the caller.
     71         CFMutableDictionaryRef dict =
     72             CFDictionaryCreateMutable(kCFAllocatorDefault,
     73                                       dict_value->size(),
     74                                       &kCFTypeDictionaryKeyCallBacks,
     75                                       &kCFTypeDictionaryValueCallBacks);
     76         for (base::DictionaryValue::Iterator iterator(*dict_value);
     77              !iterator.IsAtEnd(); iterator.Advance()) {
     78           // CFDictionaryAddValue() retains both |key| and |value|, so make sure
     79           // the references are balanced.
     80           ScopedCFTypeRef<CFStringRef> key(
     81               base::SysUTF8ToCFStringRef(iterator.key()));
     82           ScopedCFTypeRef<CFPropertyListRef> cf_value(
     83               CreatePropertyFromValue(&iterator.value()));
     84           if (cf_value)
     85             CFDictionaryAddValue(dict, key, cf_value);
     86         }
     87         return dict;
     88       }
     89       break;
     90     }
     91 
     92     case base::Value::TYPE_LIST: {
     93       const base::ListValue* list;
     94       if (value->GetAsList(&list)) {
     95         CFMutableArrayRef array =
     96             CFArrayCreateMutable(NULL, list->GetSize(), &kCFTypeArrayCallBacks);
     97         for (base::ListValue::const_iterator it(list->begin());
     98              it != list->end(); ++it) {
     99           // CFArrayAppendValue() retains |value|, so make sure the reference
    100           // created by CreatePropertyFromValue() is released.
    101           ScopedCFTypeRef<CFPropertyListRef> cf_value(
    102               CreatePropertyFromValue(*it));
    103           if (cf_value)
    104             CFArrayAppendValue(array, cf_value);
    105         }
    106         return array;
    107       }
    108       break;
    109     }
    110 
    111     case base::Value::TYPE_BINARY:
    112       // This type isn't converted (though it can be represented as CFData)
    113       // because there's no equivalent JSON type, and policy values can only
    114       // take valid JSON values.
    115       break;
    116   }
    117 
    118   return NULL;
    119 }
    120 
    121 class TestHarness : public PolicyProviderTestHarness {
    122  public:
    123   TestHarness();
    124   virtual ~TestHarness();
    125 
    126   virtual void SetUp() OVERRIDE;
    127 
    128   virtual ConfigurationPolicyProvider* CreateProvider(
    129       const PolicyDefinitionList* policy_definition_list) OVERRIDE;
    130 
    131   virtual void InstallEmptyPolicy() OVERRIDE;
    132   virtual void InstallStringPolicy(const std::string& policy_name,
    133                                    const std::string& policy_value) OVERRIDE;
    134   virtual void InstallIntegerPolicy(const std::string& policy_name,
    135                                     int policy_value) OVERRIDE;
    136   virtual void InstallBooleanPolicy(const std::string& policy_name,
    137                                     bool policy_value) OVERRIDE;
    138   virtual void InstallStringListPolicy(
    139       const std::string& policy_name,
    140       const base::ListValue* policy_value) OVERRIDE;
    141   virtual void InstallDictionaryPolicy(
    142       const std::string& policy_name,
    143       const base::DictionaryValue* policy_value) OVERRIDE;
    144 
    145   static PolicyProviderTestHarness* Create();
    146 
    147  private:
    148   MockPreferences* prefs_;
    149 
    150   DISALLOW_COPY_AND_ASSIGN(TestHarness);
    151 };
    152 
    153 TestHarness::TestHarness()
    154     : PolicyProviderTestHarness(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER) {}
    155 
    156 TestHarness::~TestHarness() {}
    157 
    158 void TestHarness::SetUp() {}
    159 
    160 ConfigurationPolicyProvider* TestHarness::CreateProvider(
    161     const PolicyDefinitionList* policy_definition_list) {
    162   prefs_ = new MockPreferences();
    163   scoped_ptr<AsyncPolicyLoader> loader(
    164       new PolicyLoaderMac(policy_definition_list, prefs_));
    165   return new AsyncPolicyProvider(loader.Pass());
    166 }
    167 
    168 void TestHarness::InstallEmptyPolicy() {}
    169 
    170 void TestHarness::InstallStringPolicy(const std::string& policy_name,
    171                                       const std::string& policy_value) {
    172   ScopedCFTypeRef<CFStringRef> name(base::SysUTF8ToCFStringRef(policy_name));
    173   ScopedCFTypeRef<CFStringRef> value(base::SysUTF8ToCFStringRef(policy_value));
    174   prefs_->AddTestItem(name, value, true);
    175 }
    176 
    177 void TestHarness::InstallIntegerPolicy(const std::string& policy_name,
    178                                        int policy_value) {
    179   ScopedCFTypeRef<CFStringRef> name(base::SysUTF8ToCFStringRef(policy_name));
    180   ScopedCFTypeRef<CFNumberRef> value(
    181       CFNumberCreate(NULL, kCFNumberIntType, &policy_value));
    182   prefs_->AddTestItem(name, value, true);
    183 }
    184 
    185 void TestHarness::InstallBooleanPolicy(const std::string& policy_name,
    186                                        bool policy_value) {
    187   ScopedCFTypeRef<CFStringRef> name(base::SysUTF8ToCFStringRef(policy_name));
    188   prefs_->AddTestItem(name,
    189                       policy_value ? kCFBooleanTrue : kCFBooleanFalse,
    190                       true);
    191 }
    192 
    193 void TestHarness::InstallStringListPolicy(const std::string& policy_name,
    194                                           const base::ListValue* policy_value) {
    195   ScopedCFTypeRef<CFStringRef> name(base::SysUTF8ToCFStringRef(policy_name));
    196   ScopedCFTypeRef<CFPropertyListRef> array(
    197       CreatePropertyFromValue(policy_value));
    198   ASSERT_TRUE(array);
    199   prefs_->AddTestItem(name, array, true);
    200 }
    201 
    202 void TestHarness::InstallDictionaryPolicy(
    203     const std::string& policy_name,
    204     const base::DictionaryValue* policy_value) {
    205   ScopedCFTypeRef<CFStringRef> name(base::SysUTF8ToCFStringRef(policy_name));
    206   ScopedCFTypeRef<CFPropertyListRef> dict(
    207       CreatePropertyFromValue(policy_value));
    208   ASSERT_TRUE(dict);
    209   prefs_->AddTestItem(name, dict, true);
    210 }
    211 
    212 // static
    213 PolicyProviderTestHarness* TestHarness::Create() {
    214   return new TestHarness();
    215 }
    216 
    217 }  // namespace
    218 
    219 // Instantiate abstract test case for basic policy reading tests.
    220 INSTANTIATE_TEST_CASE_P(
    221     PolicyProviderMacTest,
    222     ConfigurationPolicyProviderTest,
    223     testing::Values(TestHarness::Create));
    224 
    225 // TODO(joaodasilva): instantiate Configuration3rdPartyPolicyProviderTest too
    226 // once the mac loader supports 3rd party policy. http://crbug.com/108995
    227 
    228 // Special test cases for some mac preferences details.
    229 class PolicyLoaderMacTest : public PolicyTestBase {
    230  protected:
    231   PolicyLoaderMacTest()
    232       : prefs_(new MockPreferences()),
    233         loader_(new PolicyLoaderMac(&test_policy_definitions::kList, prefs_)),
    234         provider_(scoped_ptr<AsyncPolicyLoader>(loader_)) {}
    235   virtual ~PolicyLoaderMacTest() {}
    236 
    237   virtual void SetUp() OVERRIDE {
    238     PolicyTestBase::SetUp();
    239     provider_.Init();
    240   }
    241 
    242   virtual void TearDown() OVERRIDE {
    243     provider_.Shutdown();
    244     PolicyTestBase::TearDown();
    245   }
    246 
    247   MockPreferences* prefs_;
    248   PolicyLoaderMac* loader_;
    249   AsyncPolicyProvider provider_;
    250 };
    251 
    252 TEST_F(PolicyLoaderMacTest, Invalid) {
    253   ScopedCFTypeRef<CFStringRef> name(
    254       base::SysUTF8ToCFStringRef(test_policy_definitions::kKeyString));
    255   const char buffer[] = "binary \xde\xad\xbe\xef data";
    256   ScopedCFTypeRef<CFDataRef> invalid_data(
    257       CFDataCreate(kCFAllocatorDefault,
    258                    reinterpret_cast<const UInt8 *>(buffer),
    259                    arraysize(buffer)));
    260   ASSERT_TRUE(invalid_data);
    261   prefs_->AddTestItem(name, invalid_data.get(), true);
    262   prefs_->AddTestItem(name, invalid_data.get(), false);
    263 
    264   // Make the provider read the updated |prefs_|.
    265   provider_.RefreshPolicies();
    266   loop_.RunUntilIdle();
    267   const PolicyBundle kEmptyBundle;
    268   EXPECT_TRUE(provider_.policies().Equals(kEmptyBundle));
    269 }
    270 
    271 TEST_F(PolicyLoaderMacTest, TestNonForcedValue) {
    272   ScopedCFTypeRef<CFStringRef> name(
    273       base::SysUTF8ToCFStringRef(test_policy_definitions::kKeyString));
    274   ScopedCFTypeRef<CFPropertyListRef> test_value(
    275       base::SysUTF8ToCFStringRef("string value"));
    276   ASSERT_TRUE(test_value.get());
    277   prefs_->AddTestItem(name, test_value.get(), false);
    278 
    279   // Make the provider read the updated |prefs_|.
    280   provider_.RefreshPolicies();
    281   loop_.RunUntilIdle();
    282   PolicyBundle expected_bundle;
    283   expected_bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
    284       .Set(test_policy_definitions::kKeyString,
    285            POLICY_LEVEL_RECOMMENDED,
    286            POLICY_SCOPE_USER,
    287            base::Value::CreateStringValue("string value"),
    288            NULL);
    289   EXPECT_TRUE(provider_.policies().Equals(expected_bundle));
    290 }
    291 
    292 TEST_F(PolicyLoaderMacTest, TestConversions) {
    293   base::DictionaryValue root;
    294 
    295   // base::Value::TYPE_NULL
    296   root.Set("null", base::Value::CreateNullValue());
    297 
    298   // base::Value::TYPE_BOOLEAN
    299   root.SetBoolean("false", false);
    300   root.SetBoolean("true", true);
    301 
    302   // base::Value::TYPE_INTEGER
    303   root.SetInteger("int", 123);
    304   root.SetInteger("zero", 0);
    305 
    306   // base::Value::TYPE_DOUBLE
    307   root.SetDouble("double", 123.456);
    308   root.SetDouble("zerod", 0.0);
    309 
    310   // base::Value::TYPE_STRING
    311   root.SetString("string", "the fox jumps over something");
    312   root.SetString("empty", "");
    313 
    314   // base::Value::TYPE_LIST
    315   base::ListValue list;
    316   root.Set("emptyl", list.DeepCopy());
    317   for (base::DictionaryValue::Iterator it(root); !it.IsAtEnd(); it.Advance())
    318     list.Append(it.value().DeepCopy());
    319   EXPECT_EQ(root.size(), list.GetSize());
    320   list.Append(root.DeepCopy());
    321   root.Set("list", list.DeepCopy());
    322 
    323   // base::Value::TYPE_DICTIONARY
    324   base::DictionaryValue dict;
    325   root.Set("emptyd", dict.DeepCopy());
    326   // Very meta.
    327   root.Set("dict", root.DeepCopy());
    328 
    329   ScopedCFTypeRef<CFPropertyListRef> property(CreatePropertyFromValue(&root));
    330   ASSERT_TRUE(property);
    331   scoped_ptr<base::Value> value(
    332       PolicyLoaderMac::CreateValueFromProperty(property));
    333   ASSERT_TRUE(value.get());
    334 
    335   EXPECT_TRUE(root.Equals(value.get()));
    336 }
    337 
    338 }  // namespace policy
    339