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
22using testing::_;
23using testing::Mock;
24
25namespace extensions {
26
27namespace {
28
29const char kTestExtensionId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
30
31class 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.
42class 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
78ValueStore* Param(const base::FilePath& file_path) {
79  return new MutablePolicyValueStore(file_path);
80}
81
82}  // namespace
83
84INSTANTIATE_TEST_CASE_P(
85    PolicyValueStoreTest,
86    ValueStoreTest,
87    testing::Values(&Param));
88
89class 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
120TEST_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
138TEST_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
155TEST_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