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 "chrome/browser/extensions/api/storage/policy_value_store.h" 6 7 #include "base/callback.h" 8 #include "base/files/file_path.h" 9 #include "base/files/scoped_temp_dir.h" 10 #include "base/memory/ref_counted.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/message_loop/message_loop.h" 13 #include "components/policy/core/common/external_data_fetcher.h" 14 #include "components/policy/core/common/policy_map.h" 15 #include "content/public/test/test_browser_thread.h" 16 #include "extensions/browser/api/storage/settings_observer.h" 17 #include "extensions/browser/value_store/leveldb_value_store.h" 18 #include "extensions/browser/value_store/value_store_unittest.h" 19 #include "testing/gmock/include/gmock/gmock.h" 20 #include "testing/gtest/include/gtest/gtest.h" 21 22 using testing::_; 23 using testing::Mock; 24 25 namespace extensions { 26 27 namespace { 28 29 const char kTestExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 30 31 class MockSettingsObserver : public SettingsObserver { 32 public: 33 MOCK_METHOD3(OnSettingsChanged, void( 34 const std::string& extension_id, 35 settings_namespace::Namespace settings_namespace, 36 const std::string& changes_json)); 37 }; 38 39 // Extends PolicyValueStore by overriding the mutating methods, so that the 40 // Get() base implementation can be tested with the ValueStoreTest parameterized 41 // tests. 42 class MutablePolicyValueStore : public PolicyValueStore { 43 public: 44 explicit MutablePolicyValueStore(const base::FilePath& path) 45 : PolicyValueStore(kTestExtensionId, 46 make_scoped_refptr(new SettingsObserverList()), 47 scoped_ptr<ValueStore>(new LeveldbValueStore(path))) {} 48 virtual ~MutablePolicyValueStore() {} 49 50 virtual WriteResult Set( 51 WriteOptions options, 52 const std::string& key, 53 const base::Value& value) OVERRIDE { 54 return delegate()->Set(options, key, value); 55 } 56 57 virtual WriteResult Set( 58 WriteOptions options, const base::DictionaryValue& values) OVERRIDE { 59 return delegate()->Set(options, values); 60 } 61 62 virtual WriteResult Remove(const std::string& key) OVERRIDE { 63 return delegate()->Remove(key); 64 } 65 66 virtual WriteResult Remove(const std::vector<std::string>& keys) OVERRIDE { 67 return delegate()->Remove(keys); 68 } 69 70 virtual WriteResult Clear() OVERRIDE { 71 return delegate()->Clear(); 72 } 73 74 private: 75 DISALLOW_COPY_AND_ASSIGN(MutablePolicyValueStore); 76 }; 77 78 ValueStore* Param(const base::FilePath& file_path) { 79 return new MutablePolicyValueStore(file_path); 80 } 81 82 } // namespace 83 84 INSTANTIATE_TEST_CASE_P( 85 PolicyValueStoreTest, 86 ValueStoreTest, 87 testing::Values(&Param)); 88 89 class PolicyValueStoreTest : public testing::Test { 90 public: 91 PolicyValueStoreTest() 92 : file_thread_(content::BrowserThread::FILE, &loop_) {} 93 virtual ~PolicyValueStoreTest() {} 94 95 virtual void SetUp() OVERRIDE { 96 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); 97 observers_ = new SettingsObserverList(); 98 observers_->AddObserver(&observer_); 99 store_.reset(new PolicyValueStore( 100 kTestExtensionId, 101 observers_, 102 scoped_ptr<ValueStore>( 103 new LeveldbValueStore(scoped_temp_dir_.path())))); 104 } 105 106 virtual void TearDown() OVERRIDE { 107 observers_->RemoveObserver(&observer_); 108 store_.reset(); 109 } 110 111 protected: 112 base::ScopedTempDir scoped_temp_dir_; 113 base::MessageLoop loop_; 114 content::TestBrowserThread file_thread_; 115 scoped_ptr<PolicyValueStore> store_; 116 MockSettingsObserver observer_; 117 scoped_refptr<SettingsObserverList> observers_; 118 }; 119 120 TEST_F(PolicyValueStoreTest, DontProvideRecommendedPolicies) { 121 policy::PolicyMap policies; 122 base::FundamentalValue expected(123); 123 policies.Set("must", policy::POLICY_LEVEL_MANDATORY, 124 policy::POLICY_SCOPE_USER, expected.DeepCopy(), NULL); 125 policies.Set("may", policy::POLICY_LEVEL_RECOMMENDED, 126 policy::POLICY_SCOPE_USER, 127 new base::FundamentalValue(456), NULL); 128 store_->SetCurrentPolicy(policies); 129 ValueStore::ReadResult result = store_->Get(); 130 ASSERT_FALSE(result->HasError()); 131 EXPECT_EQ(1u, result->settings().size()); 132 base::Value* value = NULL; 133 EXPECT_FALSE(result->settings().Get("may", &value)); 134 EXPECT_TRUE(result->settings().Get("must", &value)); 135 EXPECT_TRUE(base::Value::Equals(&expected, value)); 136 } 137 138 TEST_F(PolicyValueStoreTest, ReadOnly) { 139 ValueStore::WriteOptions options = ValueStore::DEFAULTS; 140 141 base::StringValue string_value("value"); 142 EXPECT_TRUE(store_->Set(options, "key", string_value)->HasError()); 143 144 base::DictionaryValue dict; 145 dict.SetString("key", "value"); 146 EXPECT_TRUE(store_->Set(options, dict)->HasError()); 147 148 EXPECT_TRUE(store_->Remove("key")->HasError()); 149 std::vector<std::string> keys; 150 keys.push_back("key"); 151 EXPECT_TRUE(store_->Remove(keys)->HasError()); 152 EXPECT_TRUE(store_->Clear()->HasError()); 153 } 154 155 TEST_F(PolicyValueStoreTest, NotifyOnChanges) { 156 // Notify when setting the initial policy. 157 const base::StringValue value("111"); 158 { 159 ValueStoreChangeList changes; 160 changes.push_back(ValueStoreChange("aaa", NULL, value.DeepCopy())); 161 EXPECT_CALL(observer_, 162 OnSettingsChanged(kTestExtensionId, 163 settings_namespace::MANAGED, 164 ValueStoreChange::ToJson(changes))); 165 } 166 167 policy::PolicyMap policies; 168 policies.Set("aaa", policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, 169 value.DeepCopy(), NULL); 170 store_->SetCurrentPolicy(policies); 171 loop_.RunUntilIdle(); 172 Mock::VerifyAndClearExpectations(&observer_); 173 174 // Notify when new policies are added. 175 { 176 ValueStoreChangeList changes; 177 changes.push_back(ValueStoreChange("bbb", NULL, value.DeepCopy())); 178 EXPECT_CALL(observer_, 179 OnSettingsChanged(kTestExtensionId, 180 settings_namespace::MANAGED, 181 ValueStoreChange::ToJson(changes))); 182 } 183 184 policies.Set("bbb", policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, 185 value.DeepCopy(), NULL); 186 store_->SetCurrentPolicy(policies); 187 loop_.RunUntilIdle(); 188 Mock::VerifyAndClearExpectations(&observer_); 189 190 // Notify when policies change. 191 const base::StringValue new_value("222"); 192 { 193 ValueStoreChangeList changes; 194 changes.push_back( 195 ValueStoreChange("bbb", value.DeepCopy(), new_value.DeepCopy())); 196 EXPECT_CALL(observer_, 197 OnSettingsChanged(kTestExtensionId, 198 settings_namespace::MANAGED, 199 ValueStoreChange::ToJson(changes))); 200 } 201 202 policies.Set("bbb", policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER, 203 new_value.DeepCopy(), NULL); 204 store_->SetCurrentPolicy(policies); 205 loop_.RunUntilIdle(); 206 Mock::VerifyAndClearExpectations(&observer_); 207 208 // Notify when policies are removed. 209 { 210 ValueStoreChangeList changes; 211 changes.push_back(ValueStoreChange("bbb", new_value.DeepCopy(), NULL)); 212 EXPECT_CALL(observer_, 213 OnSettingsChanged(kTestExtensionId, 214 settings_namespace::MANAGED, 215 ValueStoreChange::ToJson(changes))); 216 } 217 218 policies.Erase("bbb"); 219 store_->SetCurrentPolicy(policies); 220 loop_.RunUntilIdle(); 221 Mock::VerifyAndClearExpectations(&observer_); 222 223 // Don't notify when there aren't any changes. 224 EXPECT_CALL(observer_, OnSettingsChanged(_, _, _)).Times(0); 225 store_->SetCurrentPolicy(policies); 226 loop_.RunUntilIdle(); 227 Mock::VerifyAndClearExpectations(&observer_); 228 } 229 230 } // namespace extensions 231