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