preference_api_prefs_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright 2013 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 <string>
6
7#include "base/memory/ref_counted.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/prefs/mock_pref_change_callback.h"
10#include "base/values.h"
11#include "chrome/browser/extensions/api/preference/preference_api.h"
12#include "chrome/browser/extensions/extension_prefs.h"
13#include "chrome/browser/extensions/extension_prefs_unittest.h"
14#include "chrome/common/extensions/extension.h"
15#include "chrome/common/extensions/extension_manifest_constants.h"
16#include "chrome/test/base/testing_profile.h"
17#include "components/user_prefs/pref_registry_syncable.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20using base::Value;
21
22namespace keys = extension_manifest_keys;
23
24namespace extensions {
25
26namespace {
27
28const char kPref1[] = "path1.subpath";
29const char kPref2[] = "path2";
30const char kPref3[] = "path3";
31const char kPref4[] = "path4";
32
33// Default values in case an extension pref value is not overridden.
34const char kDefaultPref1[] = "default pref 1";
35const char kDefaultPref2[] = "default pref 2";
36const char kDefaultPref3[] = "default pref 3";
37const char kDefaultPref4[] = "default pref 4";
38
39}  // namespace
40
41// An implementation of the PreferenceAPI which returns the ExtensionPrefs and
42// ExtensionPrefValueMap from the TestExtensionPrefs, rather than from a
43// profile (which we don't create in unittests).
44class TestPreferenceAPI : public PreferenceAPIBase {
45 public:
46  explicit TestPreferenceAPI(TestExtensionPrefs* test_extension_prefs)
47      : test_extension_prefs_(test_extension_prefs) { }
48  ~TestPreferenceAPI() { }
49 private:
50  // PreferenceAPIBase implementation.
51  virtual ExtensionPrefs* extension_prefs() OVERRIDE {
52    return test_extension_prefs_->prefs();
53  }
54  virtual ExtensionPrefValueMap* extension_pref_value_map() OVERRIDE {
55    return test_extension_prefs_->extension_pref_value_map();
56  }
57
58  TestExtensionPrefs* test_extension_prefs_;
59
60  DISALLOW_COPY_AND_ASSIGN(TestPreferenceAPI);
61};
62
63class ExtensionControlledPrefsTest : public PrefsPrepopulatedTestBase {
64 public:
65  ExtensionControlledPrefsTest();
66  virtual ~ExtensionControlledPrefsTest();
67
68  virtual void RegisterPreferences(user_prefs::PrefRegistrySyncable* registry)
69      OVERRIDE;
70  void InstallExtensionControlledPref(Extension* extension,
71                                      const std::string& key,
72                                      base::Value* value);
73  void InstallExtensionControlledPrefIncognito(Extension* extension,
74                                               const std::string& key,
75                                               base::Value* value);
76  void InstallExtensionControlledPrefIncognitoSessionOnly(
77      Extension* extension,
78      const std::string& key,
79      base::Value* value);
80  void InstallExtension(Extension* extension);
81  void UninstallExtension(const std::string& extension_id);
82
83 protected:
84  void EnsureExtensionInstalled(Extension* extension);
85  void EnsureExtensionUninstalled(const std::string& extension_id);
86
87  TestPreferenceAPI test_preference_api_;
88};
89
90ExtensionControlledPrefsTest::ExtensionControlledPrefsTest()
91    : PrefsPrepopulatedTestBase(),
92      test_preference_api_(&prefs_) {
93}
94
95ExtensionControlledPrefsTest::~ExtensionControlledPrefsTest() {
96}
97
98void ExtensionControlledPrefsTest::RegisterPreferences(
99    user_prefs::PrefRegistrySyncable* registry) {
100  registry->RegisterStringPref(
101      kPref1, kDefaultPref1, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
102  registry->RegisterStringPref(
103      kPref2, kDefaultPref2, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
104  registry->RegisterStringPref(
105      kPref3, kDefaultPref3, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
106  registry->RegisterStringPref(
107      kPref4, kDefaultPref4, user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
108}
109
110void ExtensionControlledPrefsTest::InstallExtensionControlledPref(
111    Extension* extension,
112    const std::string& key,
113    Value* value) {
114  EnsureExtensionInstalled(extension);
115  test_preference_api_.SetExtensionControlledPref(
116      extension->id(), key, kExtensionPrefsScopeRegular, value);
117}
118
119void ExtensionControlledPrefsTest::InstallExtensionControlledPrefIncognito(
120    Extension* extension,
121    const std::string& key,
122    Value* value) {
123  EnsureExtensionInstalled(extension);
124  test_preference_api_.SetExtensionControlledPref(
125      extension->id(), key, kExtensionPrefsScopeIncognitoPersistent, value);
126}
127
128void ExtensionControlledPrefsTest::
129InstallExtensionControlledPrefIncognitoSessionOnly(Extension* extension,
130                                                   const std::string& key,
131                                                   Value* value) {
132  EnsureExtensionInstalled(extension);
133  test_preference_api_.SetExtensionControlledPref(
134      extension->id(), key, kExtensionPrefsScopeIncognitoSessionOnly, value);
135}
136
137void ExtensionControlledPrefsTest::InstallExtension(Extension* extension) {
138  EnsureExtensionInstalled(extension);
139}
140
141void ExtensionControlledPrefsTest::UninstallExtension(
142    const std::string& extension_id) {
143  EnsureExtensionUninstalled(extension_id);
144}
145
146void ExtensionControlledPrefsTest::EnsureExtensionInstalled(
147    Extension* extension) {
148  // Install extension the first time a preference is set for it.
149  Extension* extensions[] = { extension1(),
150                              extension2(),
151                              extension3(),
152                              extension4() };
153  for (size_t i = 0; i < kNumInstalledExtensions; ++i) {
154    if (extension == extensions[i] && !installed_[i]) {
155      prefs()->OnExtensionInstalled(extension, Extension::ENABLED,
156                                    syncer::StringOrdinal());
157      installed_[i] = true;
158      break;
159    }
160  }
161}
162
163void ExtensionControlledPrefsTest::EnsureExtensionUninstalled(
164    const std::string& extension_id) {
165  Extension* extensions[] = { extension1(),
166                              extension2(),
167                              extension3(),
168                              extension4() };
169  for (size_t i = 0; i < kNumInstalledExtensions; ++i) {
170    if (extensions[i]->id() == extension_id) {
171      installed_[i] = false;
172      break;
173    }
174  }
175  prefs()->OnExtensionUninstalled(extension_id, Manifest::INTERNAL, false);
176}
177
178class ControlledPrefsInstallOneExtension
179    : public ExtensionControlledPrefsTest {
180  virtual void Initialize() OVERRIDE {
181    InstallExtensionControlledPref(extension1(),
182                                   kPref1,
183                                   Value::CreateStringValue("val1"));
184  }
185  virtual void Verify() OVERRIDE {
186    std::string actual = prefs()->pref_service()->GetString(kPref1);
187    EXPECT_EQ("val1", actual);
188  }
189};
190TEST_F(ControlledPrefsInstallOneExtension,
191       ControlledPrefsInstallOneExtension) { }
192
193// Check that we do not forget persistent incognito values after a reload.
194class ControlledPrefsInstallIncognitoPersistent
195    : public ExtensionControlledPrefsTest {
196 public:
197  virtual void Initialize() OVERRIDE {
198    InstallExtensionControlledPref(
199        extension1(), kPref1, Value::CreateStringValue("val1"));
200    InstallExtensionControlledPrefIncognito(
201        extension1(), kPref1, Value::CreateStringValue("val2"));
202    scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
203    std::string actual = incog_prefs->GetString(kPref1);
204    EXPECT_EQ("val2", actual);
205  }
206
207  virtual void Verify() OVERRIDE {
208    // Main pref service shall see only non-incognito settings.
209    std::string actual = prefs()->pref_service()->GetString(kPref1);
210    EXPECT_EQ("val1", actual);
211    // Incognito pref service shall see incognito values.
212    scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
213    actual = incog_prefs->GetString(kPref1);
214    EXPECT_EQ("val2", actual);
215  }
216};
217TEST_F(ControlledPrefsInstallIncognitoPersistent,
218       ControlledPrefsInstallIncognitoPersistent) { }
219
220// Check that we forget 'session only' incognito values after a reload.
221class ControlledPrefsInstallIncognitoSessionOnly
222    : public ExtensionControlledPrefsTest {
223 public:
224  ControlledPrefsInstallIncognitoSessionOnly() : iteration_(0) {}
225
226  virtual void Initialize() OVERRIDE {
227    InstallExtensionControlledPref(
228        extension1(), kPref1, Value::CreateStringValue("val1"));
229    InstallExtensionControlledPrefIncognitoSessionOnly(
230        extension1(), kPref1, Value::CreateStringValue("val2"));
231    scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
232    std::string actual = incog_prefs->GetString(kPref1);
233    EXPECT_EQ("val2", actual);
234  }
235  virtual void Verify() OVERRIDE {
236    // Main pref service shall see only non-incognito settings.
237    std::string actual = prefs()->pref_service()->GetString(kPref1);
238    EXPECT_EQ("val1", actual);
239    // Incognito pref service shall see session-only incognito values only
240    // during first run. Once the pref service was reloaded, all values shall be
241    // discarded.
242    scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
243    actual = incog_prefs->GetString(kPref1);
244    if (iteration_ == 0) {
245      EXPECT_EQ("val2", actual);
246    } else {
247      EXPECT_EQ("val1", actual);
248    }
249    ++iteration_;
250  }
251  int iteration_;
252};
253TEST_F(ControlledPrefsInstallIncognitoSessionOnly,
254       ControlledPrefsInstallIncognitoSessionOnly) { }
255
256class ControlledPrefsUninstallExtension : public ExtensionControlledPrefsTest {
257  virtual void Initialize() OVERRIDE {
258    InstallExtensionControlledPref(
259        extension1(), kPref1, Value::CreateStringValue("val1"));
260    InstallExtensionControlledPref(
261        extension1(), kPref2, Value::CreateStringValue("val2"));
262    ContentSettingsStore* store = prefs()->content_settings_store();
263    ContentSettingsPattern pattern =
264        ContentSettingsPattern::FromString("http://[*.]example.com");
265    store->SetExtensionContentSetting(extension1()->id(),
266                                      pattern, pattern,
267                                      CONTENT_SETTINGS_TYPE_IMAGES,
268                                      std::string(),
269                                      CONTENT_SETTING_BLOCK,
270                                      kExtensionPrefsScopeRegular);
271
272    UninstallExtension(extension1()->id());
273  }
274  virtual void Verify() OVERRIDE {
275    EXPECT_FALSE(prefs()->HasPrefForExtension(extension1()->id()));
276
277    std::string actual;
278    actual = prefs()->pref_service()->GetString(kPref1);
279    EXPECT_EQ(kDefaultPref1, actual);
280    actual = prefs()->pref_service()->GetString(kPref2);
281    EXPECT_EQ(kDefaultPref2, actual);
282  }
283};
284TEST_F(ControlledPrefsUninstallExtension,
285       ControlledPrefsUninstallExtension) { }
286
287// Tests triggering of notifications to registered observers.
288class ControlledPrefsNotifyWhenNeeded : public ExtensionControlledPrefsTest {
289  virtual void Initialize() OVERRIDE {
290    using testing::_;
291    using testing::Mock;
292    using testing::StrEq;
293
294    MockPrefChangeCallback observer(prefs()->pref_service());
295    PrefChangeRegistrar registrar;
296    registrar.Init(prefs()->pref_service());
297    registrar.Add(kPref1, observer.GetCallback());
298
299    MockPrefChangeCallback incognito_observer(prefs()->pref_service());
300    scoped_ptr<PrefService> incog_prefs(prefs_.CreateIncognitoPrefService());
301    PrefChangeRegistrar incognito_registrar;
302    incognito_registrar.Init(incog_prefs.get());
303    incognito_registrar.Add(kPref1, incognito_observer.GetCallback());
304
305    // Write value and check notification.
306    EXPECT_CALL(observer, OnPreferenceChanged(_));
307    EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
308    InstallExtensionControlledPref(extension1(), kPref1,
309        Value::CreateStringValue("https://www.chromium.org"));
310    Mock::VerifyAndClearExpectations(&observer);
311    Mock::VerifyAndClearExpectations(&incognito_observer);
312
313    // Write same value.
314    EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
315    EXPECT_CALL(incognito_observer, OnPreferenceChanged(_)).Times(0);
316    InstallExtensionControlledPref(extension1(), kPref1,
317        Value::CreateStringValue("https://www.chromium.org"));
318    Mock::VerifyAndClearExpectations(&observer);
319    Mock::VerifyAndClearExpectations(&incognito_observer);
320
321    // Change value.
322    EXPECT_CALL(observer, OnPreferenceChanged(_));
323    EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
324    InstallExtensionControlledPref(extension1(), kPref1,
325        Value::CreateStringValue("chrome://newtab"));
326    Mock::VerifyAndClearExpectations(&observer);
327    Mock::VerifyAndClearExpectations(&incognito_observer);
328    // Change only incognito persistent value.
329    EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
330    EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
331    InstallExtensionControlledPrefIncognito(extension1(), kPref1,
332        Value::CreateStringValue("chrome://newtab2"));
333    Mock::VerifyAndClearExpectations(&observer);
334    Mock::VerifyAndClearExpectations(&incognito_observer);
335
336    // Change only incognito session-only value.
337    EXPECT_CALL(observer, OnPreferenceChanged(_)).Times(0);
338    EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
339    InstallExtensionControlledPrefIncognito(extension1(), kPref1,
340        Value::CreateStringValue("chrome://newtab3"));
341    Mock::VerifyAndClearExpectations(&observer);
342    Mock::VerifyAndClearExpectations(&incognito_observer);
343
344    // Uninstall.
345    EXPECT_CALL(observer, OnPreferenceChanged(_));
346    EXPECT_CALL(incognito_observer, OnPreferenceChanged(_));
347    UninstallExtension(extension1()->id());
348    Mock::VerifyAndClearExpectations(&observer);
349    Mock::VerifyAndClearExpectations(&incognito_observer);
350
351    registrar.Remove(kPref1);
352    incognito_registrar.Remove(kPref1);
353  }
354  virtual void Verify() OVERRIDE {
355    std::string actual = prefs()->pref_service()->GetString(kPref1);
356    EXPECT_EQ(kDefaultPref1, actual);
357  }
358};
359TEST_F(ControlledPrefsNotifyWhenNeeded,
360       ControlledPrefsNotifyWhenNeeded) { }
361
362// Tests disabling an extension.
363class ControlledPrefsDisableExtension : public ExtensionControlledPrefsTest {
364  virtual void Initialize() OVERRIDE {
365    InstallExtensionControlledPref(
366        extension1(), kPref1, Value::CreateStringValue("val1"));
367    std::string actual = prefs()->pref_service()->GetString(kPref1);
368    EXPECT_EQ("val1", actual);
369    prefs()->SetExtensionState(extension1()->id(), Extension::DISABLED);
370  }
371  virtual void Verify() OVERRIDE {
372    std::string actual = prefs()->pref_service()->GetString(kPref1);
373    EXPECT_EQ(kDefaultPref1, actual);
374  }
375};
376TEST_F(ControlledPrefsDisableExtension, ControlledPrefsDisableExtension) { }
377
378// Tests disabling and reenabling an extension.
379class ControlledPrefsReenableExtension : public ExtensionControlledPrefsTest {
380  virtual void Initialize() OVERRIDE {
381    InstallExtensionControlledPref(
382        extension1(), kPref1, Value::CreateStringValue("val1"));
383    prefs()->SetExtensionState(extension1()->id(), Extension::DISABLED);
384    prefs()->SetExtensionState(extension1()->id(), Extension::ENABLED);
385  }
386  virtual void Verify() OVERRIDE {
387    std::string actual = prefs()->pref_service()->GetString(kPref1);
388    EXPECT_EQ("val1", actual);
389  }
390};
391TEST_F(ControlledPrefsDisableExtension, ControlledPrefsReenableExtension) { }
392
393// Mock class to test whether objects are deleted correctly.
394class MockStringValue : public StringValue {
395 public:
396  explicit MockStringValue(const std::string& in_value)
397      : StringValue(in_value) {
398  }
399  virtual ~MockStringValue() {
400    Die();
401  }
402  MOCK_METHOD0(Die, void());
403};
404
405class ControlledPrefsSetExtensionControlledPref
406    : public ExtensionControlledPrefsTest {
407 public:
408  virtual void Initialize() OVERRIDE {
409    MockStringValue* v1 = new MockStringValue("https://www.chromium.org");
410    MockStringValue* v2 = new MockStringValue("https://www.chromium.org");
411    MockStringValue* v1i = new MockStringValue("https://www.chromium.org");
412    MockStringValue* v2i = new MockStringValue("https://www.chromium.org");
413    // Ownership is taken, value shall not be deleted.
414    EXPECT_CALL(*v1, Die()).Times(0);
415    EXPECT_CALL(*v1i, Die()).Times(0);
416    InstallExtensionControlledPref(extension1(), kPref1, v1);
417    InstallExtensionControlledPrefIncognito(extension1(), kPref1, v1i);
418    testing::Mock::VerifyAndClearExpectations(v1);
419    testing::Mock::VerifyAndClearExpectations(v1i);
420    // Make sure there is no memory leak and both values are deleted.
421    EXPECT_CALL(*v1, Die()).Times(1);
422    EXPECT_CALL(*v1i, Die()).Times(1);
423    EXPECT_CALL(*v2, Die()).Times(1);
424    EXPECT_CALL(*v2i, Die()).Times(1);
425    InstallExtensionControlledPref(extension1(), kPref1, v2);
426    InstallExtensionControlledPrefIncognito(extension1(), kPref1, v2i);
427    prefs_.RecreateExtensionPrefs();
428    testing::Mock::VerifyAndClearExpectations(v1);
429    testing::Mock::VerifyAndClearExpectations(v1i);
430    testing::Mock::VerifyAndClearExpectations(v2);
431    testing::Mock::VerifyAndClearExpectations(v2i);
432  }
433
434  virtual void Verify() OVERRIDE {
435  }
436};
437TEST_F(ControlledPrefsSetExtensionControlledPref,
438       ControlledPrefsSetExtensionControlledPref) { }
439
440// Tests that the switches::kDisableExtensions command-line flag prevents
441// extension controlled preferences from being enacted.
442class ControlledPrefsDisableExtensions : public ExtensionControlledPrefsTest {
443 public:
444  ControlledPrefsDisableExtensions()
445      : iteration_(0) {}
446  virtual ~ControlledPrefsDisableExtensions() {}
447  virtual void Initialize() OVERRIDE {
448    InstallExtensionControlledPref(
449        extension1(), kPref1, Value::CreateStringValue("val1"));
450    // This becomes only active in the second verification phase.
451    prefs_.set_extensions_disabled(true);
452  }
453  virtual void Verify() OVERRIDE {
454    std::string actual = prefs()->pref_service()->GetString(kPref1);
455    if (iteration_ == 0) {
456      EXPECT_EQ("val1", actual);
457      ++iteration_;
458    } else {
459      EXPECT_EQ(kDefaultPref1, actual);
460    }
461  }
462
463 private:
464  int iteration_;
465};
466TEST_F(ControlledPrefsDisableExtensions, ControlledPrefsDisableExtensions) { }
467
468}  // namespace extensions
469