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/test_extension_prefs.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/files/file_util.h"
13 #include "base/macros.h"
14 #include "base/run_loop.h"
15 #include "base/sequenced_task_runner.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/thread_task_runner_handle.h"
18 #include "base/time/clock.h"
19 #include "base/values.h"
20 #include "chrome/browser/extensions/chrome_app_sorting.h"
21 #include "chrome/browser/extensions/test_extension_system.h"
22 #include "chrome/browser/prefs/browser_prefs.h"
23 #include "chrome/browser/prefs/pref_service_syncable_util.h"
24 #include "chrome/common/chrome_constants.h"
25 #include "components/crx_file/id_util.h"
26 #include "components/pref_registry/pref_registry_syncable.h"
27 #include "components/prefs/json_pref_store.h"
28 #include "components/prefs/pref_value_store.h"
29 #include "components/sync/model/string_ordinal.h"
30 #include "components/sync_preferences/pref_service_mock_factory.h"
31 #include "components/sync_preferences/pref_service_syncable.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "extensions/browser/extension_pref_store.h"
34 #include "extensions/browser/extension_pref_value_map.h"
35 #include "extensions/browser/extension_prefs.h"
36 #include "extensions/browser/extension_prefs_factory.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/browser/extensions_browser_client.h"
39 #include "extensions/common/extension.h"
40 #include "extensions/common/manifest_constants.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42
43 using content::BrowserThread;
44
45 namespace extensions {
46
47 // A Clock which returns an incrementally later time each time Now() is called.
48 class TestExtensionPrefs::IncrementalClock : public base::Clock {
49 public:
IncrementalClock()50 IncrementalClock() : current_time_(base::Time::Now()) {}
51
~IncrementalClock()52 ~IncrementalClock() override {}
53
Now() const54 base::Time Now() const override {
55 current_time_ += base::TimeDelta::FromSeconds(10);
56 return current_time_;
57 }
58
59 private:
60 mutable base::Time current_time_;
61
62 DISALLOW_COPY_AND_ASSIGN(IncrementalClock);
63 };
64
TestExtensionPrefs(const scoped_refptr<base::SequencedTaskRunner> & task_runner)65 TestExtensionPrefs::TestExtensionPrefs(
66 const scoped_refptr<base::SequencedTaskRunner>& task_runner)
67 : task_runner_(task_runner),
68 clock_(std::make_unique<IncrementalClock>()),
69 extensions_disabled_(false) {
70 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
71 preferences_file_ = temp_dir_.GetPath().Append(chrome::kPreferencesFilename);
72 extensions_dir_ = temp_dir_.GetPath().AppendASCII("Extensions");
73 EXPECT_TRUE(base::CreateDirectory(extensions_dir_));
74
75 ResetPrefRegistry();
76 RecreateExtensionPrefs();
77 }
78
~TestExtensionPrefs()79 TestExtensionPrefs::~TestExtensionPrefs() {
80 }
81
prefs()82 ExtensionPrefs* TestExtensionPrefs::prefs() {
83 return ExtensionPrefs::Get(&profile_);
84 }
85
profile()86 TestingProfile* TestExtensionPrefs::profile() {
87 return &profile_;
88 }
89
pref_service()90 PrefService* TestExtensionPrefs::pref_service() {
91 return pref_service_.get();
92 }
93
94 const scoped_refptr<user_prefs::PrefRegistrySyncable>&
pref_registry()95 TestExtensionPrefs::pref_registry() {
96 return pref_registry_;
97 }
98
ResetPrefRegistry()99 void TestExtensionPrefs::ResetPrefRegistry() {
100 pref_registry_ = new user_prefs::PrefRegistrySyncable;
101 RegisterUserProfilePrefs(pref_registry_.get());
102 }
103
RecreateExtensionPrefs()104 void TestExtensionPrefs::RecreateExtensionPrefs() {
105 // We persist and reload the PrefService's PrefStores because this process
106 // deletes all empty dictionaries. The ExtensionPrefs implementation
107 // needs to be able to handle this situation.
108 if (pref_service_) {
109 // Commit a pending write (which posts a task to task_runner_) and wait for
110 // it to finish.
111 pref_service_->CommitPendingWrite();
112 base::RunLoop run_loop;
113 ASSERT_TRUE(task_runner_->PostTaskAndReply(FROM_HERE, base::DoNothing(),
114 run_loop.QuitClosure()));
115 run_loop.Run();
116 }
117
118 extension_pref_value_map_.reset(new ExtensionPrefValueMap);
119 sync_preferences::PrefServiceMockFactory factory;
120 factory.SetUserPrefsFile(preferences_file_, task_runner_.get());
121 factory.set_extension_prefs(
122 new ExtensionPrefStore(extension_pref_value_map_.get(), false));
123 pref_service_ = factory.CreateSyncable(pref_registry_.get());
124 std::unique_ptr<ExtensionPrefs> prefs(ExtensionPrefs::Create(
125 &profile_, pref_service_.get(), temp_dir_.GetPath(),
126 extension_pref_value_map_.get(), extensions_disabled_,
127 std::vector<EarlyExtensionPrefsObserver*>(),
128 // Guarantee that no two extensions get the same installation time
129 // stamp and we can reliably assert the installation order in the tests.
130 clock_.get()));
131 ExtensionPrefsFactory::GetInstance()->SetInstanceForTesting(&profile_,
132 std::move(prefs));
133 // Hack: After recreating ExtensionPrefs, the AppSorting also needs to be
134 // recreated. (ExtensionPrefs is never recreated in non-test code.)
135 static_cast<TestExtensionSystem*>(ExtensionSystem::Get(&profile_))
136 ->RecreateAppSorting();
137 }
138
AddExtension(const std::string & name)139 scoped_refptr<Extension> TestExtensionPrefs::AddExtension(
140 const std::string& name) {
141 return AddExtensionWithLocation(name, Manifest::INTERNAL);
142 }
143
AddApp(const std::string & name)144 scoped_refptr<Extension> TestExtensionPrefs::AddApp(const std::string& name) {
145 base::DictionaryValue dictionary;
146 dictionary.SetString(manifest_keys::kName, name);
147 dictionary.SetString(manifest_keys::kVersion, "0.1");
148 dictionary.SetString(manifest_keys::kApp, "true");
149 dictionary.SetString(manifest_keys::kLaunchWebURL, "http://example.com");
150 return AddExtensionWithManifest(dictionary, Manifest::INTERNAL);
151
152 }
153
AddExtensionWithLocation(const std::string & name,Manifest::Location location)154 scoped_refptr<Extension> TestExtensionPrefs::AddExtensionWithLocation(
155 const std::string& name,
156 Manifest::Location location) {
157 base::DictionaryValue dictionary;
158 dictionary.SetString(manifest_keys::kName, name);
159 dictionary.SetString(manifest_keys::kVersion, "0.1");
160 dictionary.SetInteger(manifest_keys::kManifestVersion, 2);
161 return AddExtensionWithManifest(dictionary, location);
162 }
163
AddExtensionWithManifest(const base::DictionaryValue & manifest,Manifest::Location location)164 scoped_refptr<Extension> TestExtensionPrefs::AddExtensionWithManifest(
165 const base::DictionaryValue& manifest, Manifest::Location location) {
166 return AddExtensionWithManifestAndFlags(manifest, location,
167 Extension::NO_FLAGS);
168 }
169
AddExtensionWithManifestAndFlags(const base::DictionaryValue & manifest,Manifest::Location location,int extra_flags)170 scoped_refptr<Extension> TestExtensionPrefs::AddExtensionWithManifestAndFlags(
171 const base::DictionaryValue& manifest,
172 Manifest::Location location,
173 int extra_flags) {
174 std::string name;
175 EXPECT_TRUE(manifest.GetString(manifest_keys::kName, &name));
176 base::FilePath path = extensions_dir_.AppendASCII(name);
177 std::string errors;
178 scoped_refptr<Extension> extension = Extension::Create(
179 path, location, manifest, extra_flags, &errors);
180 EXPECT_TRUE(extension.get()) << errors;
181 if (!extension.get())
182 return nullptr;
183
184 EXPECT_TRUE(crx_file::id_util::IdIsValid(extension->id()));
185 prefs()->OnExtensionInstalled(extension.get(),
186 Extension::ENABLED,
187 syncer::StringOrdinal::CreateInitialOrdinal(),
188 std::string());
189 return extension;
190 }
191
AddExtensionAndReturnId(const std::string & name)192 std::string TestExtensionPrefs::AddExtensionAndReturnId(
193 const std::string& name) {
194 scoped_refptr<Extension> extension(AddExtension(name));
195 return extension->id();
196 }
197
AddExtension(const Extension * extension)198 void TestExtensionPrefs::AddExtension(const Extension* extension) {
199 prefs()->OnExtensionInstalled(extension,
200 Extension::ENABLED,
201 syncer::StringOrdinal::CreateInitialOrdinal(),
202 std::string());
203 }
204
CreateIncognitoPrefService() const205 std::unique_ptr<PrefService> TestExtensionPrefs::CreateIncognitoPrefService()
206 const {
207 return CreateIncognitoPrefServiceSyncable(
208 pref_service_.get(),
209 new ExtensionPrefStore(extension_pref_value_map_.get(), true));
210 }
211
set_extensions_disabled(bool extensions_disabled)212 void TestExtensionPrefs::set_extensions_disabled(bool extensions_disabled) {
213 extensions_disabled_ = extensions_disabled;
214 }
215
app_sorting()216 ChromeAppSorting* TestExtensionPrefs::app_sorting() {
217 return static_cast<ChromeAppSorting*>(
218 ExtensionSystem::Get(&profile_)->app_sorting());
219 }
220
221 } // namespace extensions
222