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