1 // Copyright 2014 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/chromeos/file_system_provider/registry.h"
6
7 #include <memory>
8 #include <string>
9 #include <utility>
10 #include <vector>
11
12 #include "base/files/file_path.h"
13 #include "chrome/browser/chromeos/file_system_provider/icon_set.h"
14 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
15 #include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
16 #include "chrome/common/pref_names.h"
17 #include "chrome/test/base/testing_browser_process.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "chrome/test/base/testing_profile_manager.h"
20 #include "components/sync_preferences/testing_pref_service_syncable.h"
21 #include "components/user_prefs/user_prefs.h"
22 #include "content/public/test/browser_task_environment.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace chromeos {
26 namespace file_system_provider {
27 namespace {
28
29 const char kTemporaryOrigin[] =
30 "chrome-extension://abcabcabcabcabcabcabcabcabcabcabcabca/";
31 const char kPersistentOrigin[] =
32 "chrome-extension://efgefgefgefgefgefgefgefgefgefgefgefge/";
33 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
34 const char kDisplayName[] = "Camera Pictures";
35 const ProviderId kProviderId = ProviderId::CreateFromExtensionId(kExtensionId);
36
37 // The dot in the file system ID is there in order to check that saving to
38 // preferences works correctly. File System ID is used as a key in
39 // a base::DictionaryValue, so it has to be stored without path expansion.
40 const char kFileSystemId[] = "camera/pictures/id .!@#$%^&*()_+";
41
42 const int kOpenedFilesLimit = 5;
43
44 // Stores a provided file system information in preferences together with a
45 // fake watcher.
RememberFakeFileSystem(TestingProfile * profile,const ProviderId & provider_id,const std::string & file_system_id,const std::string & display_name,bool writable,bool supports_notify_tag,int opened_files_limit,const Watcher & watcher)46 void RememberFakeFileSystem(TestingProfile* profile,
47 const ProviderId& provider_id,
48 const std::string& file_system_id,
49 const std::string& display_name,
50 bool writable,
51 bool supports_notify_tag,
52 int opened_files_limit,
53 const Watcher& watcher) {
54 // Warning. Updating this code means that backward compatibility may be
55 // broken, what is unexpected and should be avoided.
56 sync_preferences::TestingPrefServiceSyncable* const pref_service =
57 profile->GetTestingPrefService();
58 ASSERT_TRUE(pref_service);
59
60 base::DictionaryValue extensions;
61 auto file_system = std::make_unique<base::DictionaryValue>();
62 file_system->SetKey(kPrefKeyFileSystemId, base::Value(kFileSystemId));
63 file_system->SetKey(kPrefKeyDisplayName, base::Value(kDisplayName));
64 file_system->SetKey(kPrefKeyWritable, base::Value(writable));
65 file_system->SetKey(kPrefKeySupportsNotifyTag,
66 base::Value(supports_notify_tag));
67 file_system->SetKey(kPrefKeyOpenedFilesLimit,
68 base::Value(opened_files_limit));
69
70 // Remember watchers.
71 auto watcher_value = std::make_unique<base::DictionaryValue>();
72 watcher_value->SetKey(kPrefKeyWatcherEntryPath,
73 base::Value(watcher.entry_path.value()));
74 watcher_value->SetKey(kPrefKeyWatcherRecursive,
75 base::Value(watcher.recursive));
76 watcher_value->SetKey(kPrefKeyWatcherLastTag, base::Value(watcher.last_tag));
77 auto persistent_origins_value = std::make_unique<base::ListValue>();
78 for (const auto& subscriber_it : watcher.subscribers) {
79 if (subscriber_it.second.persistent)
80 persistent_origins_value->AppendString(subscriber_it.first.spec());
81 }
82
83 watcher_value->SetWithoutPathExpansion(kPrefKeyWatcherPersistentOrigins,
84 std::move(persistent_origins_value));
85 auto watchers = std::make_unique<base::DictionaryValue>();
86 watchers->SetWithoutPathExpansion(watcher.entry_path.value(),
87 std::move(watcher_value));
88 file_system->SetWithoutPathExpansion(kPrefKeyWatchers, std::move(watchers));
89 auto file_systems = std::make_unique<base::DictionaryValue>();
90 file_systems->SetWithoutPathExpansion(kFileSystemId, std::move(file_system));
91 extensions.SetWithoutPathExpansion(kProviderId.ToString(),
92 std::move(file_systems));
93 pref_service->Set(prefs::kFileSystemProviderMounted, extensions);
94 }
95
96 } // namespace
97
98 class FileSystemProviderRegistryTest : public testing::Test {
99 protected:
FileSystemProviderRegistryTest()100 FileSystemProviderRegistryTest() : profile_(NULL) {}
101
~FileSystemProviderRegistryTest()102 ~FileSystemProviderRegistryTest() override {}
103
SetUp()104 void SetUp() override {
105 profile_manager_.reset(
106 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
107 ASSERT_TRUE(profile_manager_->SetUp());
108 profile_ = profile_manager_->CreateTestingProfile("test-user@example.com");
109 registry_.reset(new Registry(profile_));
110 fake_watcher_.entry_path = base::FilePath(FILE_PATH_LITERAL("/a/b/c"));
111 fake_watcher_.recursive = true;
112 fake_watcher_.subscribers[GURL(kTemporaryOrigin)].origin =
113 GURL(kTemporaryOrigin);
114 fake_watcher_.subscribers[GURL(kTemporaryOrigin)].persistent = false;
115 fake_watcher_.subscribers[GURL(kPersistentOrigin)].origin =
116 GURL(kPersistentOrigin);
117 fake_watcher_.subscribers[GURL(kPersistentOrigin)].persistent = true;
118 fake_watcher_.last_tag = "hello-world";
119 }
120
121 content::BrowserTaskEnvironment task_environment_;
122 std::unique_ptr<TestingProfileManager> profile_manager_;
123 TestingProfile* profile_;
124 std::unique_ptr<RegistryInterface> registry_;
125 Watcher fake_watcher_;
126 };
127
TEST_F(FileSystemProviderRegistryTest,RestoreFileSystems)128 TEST_F(FileSystemProviderRegistryTest, RestoreFileSystems) {
129 // Create a fake entry in the preferences.
130 RememberFakeFileSystem(profile_, kProviderId, kFileSystemId, kDisplayName,
131 true /* writable */, true /* supports_notify_tag */,
132 kOpenedFilesLimit, fake_watcher_);
133
134 std::unique_ptr<RegistryInterface::RestoredFileSystems>
135 restored_file_systems = registry_->RestoreFileSystems(kProviderId);
136
137 ASSERT_EQ(1u, restored_file_systems->size());
138 const RegistryInterface::RestoredFileSystem& restored_file_system =
139 restored_file_systems->at(0);
140 EXPECT_EQ(kProviderId, restored_file_system.provider_id);
141 EXPECT_EQ(kFileSystemId, restored_file_system.options.file_system_id);
142 EXPECT_EQ(kDisplayName, restored_file_system.options.display_name);
143 EXPECT_TRUE(restored_file_system.options.writable);
144 EXPECT_TRUE(restored_file_system.options.supports_notify_tag);
145 EXPECT_EQ(kOpenedFilesLimit, restored_file_system.options.opened_files_limit);
146
147 ASSERT_EQ(1u, restored_file_system.watchers.size());
148 const auto& restored_watcher_it = restored_file_system.watchers.find(
149 WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive));
150 ASSERT_NE(restored_file_system.watchers.end(), restored_watcher_it);
151
152 EXPECT_EQ(fake_watcher_.entry_path, restored_watcher_it->second.entry_path);
153 EXPECT_EQ(fake_watcher_.recursive, restored_watcher_it->second.recursive);
154 EXPECT_EQ(fake_watcher_.last_tag, restored_watcher_it->second.last_tag);
155 }
156
TEST_F(FileSystemProviderRegistryTest,RememberFileSystem)157 TEST_F(FileSystemProviderRegistryTest, RememberFileSystem) {
158 MountOptions options(kFileSystemId, kDisplayName);
159 options.writable = true;
160 options.supports_notify_tag = true;
161 options.opened_files_limit = kOpenedFilesLimit;
162
163 ProvidedFileSystemInfo file_system_info(
164 kProviderId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")),
165 false /* configurable */, true /* watchable */, extensions::SOURCE_FILE,
166 IconSet());
167
168 Watchers watchers;
169 watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] =
170 fake_watcher_;
171
172 registry_->RememberFileSystem(file_system_info, watchers);
173
174 sync_preferences::TestingPrefServiceSyncable* const pref_service =
175 profile_->GetTestingPrefService();
176 ASSERT_TRUE(pref_service);
177
178 const base::DictionaryValue* const extensions =
179 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
180 ASSERT_TRUE(extensions);
181
182 const base::DictionaryValue* file_systems = NULL;
183 ASSERT_TRUE(extensions->GetDictionaryWithoutPathExpansion(
184 kProviderId.ToString(), &file_systems));
185 EXPECT_EQ(1u, file_systems->size());
186
187 const base::Value* file_system_value = NULL;
188 const base::DictionaryValue* file_system = NULL;
189 ASSERT_TRUE(
190 file_systems->GetWithoutPathExpansion(kFileSystemId, &file_system_value));
191 ASSERT_TRUE(file_system_value->GetAsDictionary(&file_system));
192
193 std::string file_system_id;
194 EXPECT_TRUE(file_system->GetStringWithoutPathExpansion(kPrefKeyFileSystemId,
195 &file_system_id));
196 EXPECT_EQ(kFileSystemId, file_system_id);
197
198 std::string display_name;
199 EXPECT_TRUE(file_system->GetStringWithoutPathExpansion(kPrefKeyDisplayName,
200 &display_name));
201 EXPECT_EQ(kDisplayName, display_name);
202
203 bool writable = false;
204 EXPECT_TRUE(
205 file_system->GetBooleanWithoutPathExpansion(kPrefKeyWritable, &writable));
206 EXPECT_TRUE(writable);
207
208 bool supports_notify_tag = false;
209 EXPECT_TRUE(file_system->GetBooleanWithoutPathExpansion(
210 kPrefKeySupportsNotifyTag, &supports_notify_tag));
211 EXPECT_TRUE(supports_notify_tag);
212
213 int opened_files_limit = 0;
214 EXPECT_TRUE(file_system->GetIntegerWithoutPathExpansion(
215 kPrefKeyOpenedFilesLimit, &opened_files_limit));
216 EXPECT_EQ(kOpenedFilesLimit, opened_files_limit);
217
218 const base::DictionaryValue* watchers_value = NULL;
219 ASSERT_TRUE(file_system->GetDictionaryWithoutPathExpansion(kPrefKeyWatchers,
220 &watchers_value));
221
222 const base::DictionaryValue* watcher = NULL;
223 ASSERT_TRUE(watchers_value->GetDictionaryWithoutPathExpansion(
224 fake_watcher_.entry_path.value(), &watcher));
225
226 std::string entry_path;
227 EXPECT_TRUE(watcher->GetStringWithoutPathExpansion(kPrefKeyWatcherEntryPath,
228 &entry_path));
229 EXPECT_EQ(fake_watcher_.entry_path.value(), entry_path);
230
231 bool recursive = false;
232 EXPECT_TRUE(watcher->GetBooleanWithoutPathExpansion(kPrefKeyWatcherRecursive,
233 &recursive));
234 EXPECT_EQ(fake_watcher_.recursive, recursive);
235
236 std::string last_tag;
237 EXPECT_TRUE(watcher->GetStringWithoutPathExpansion(kPrefKeyWatcherLastTag,
238 &last_tag));
239 EXPECT_EQ(fake_watcher_.last_tag, last_tag);
240
241 const base::ListValue* persistent_origins = NULL;
242 ASSERT_TRUE(watcher->GetListWithoutPathExpansion(
243 kPrefKeyWatcherPersistentOrigins, &persistent_origins));
244 ASSERT_GT(fake_watcher_.subscribers.size(), persistent_origins->GetSize());
245 ASSERT_EQ(1u, persistent_origins->GetSize());
246 std::string persistent_origin;
247 EXPECT_TRUE(persistent_origins->GetString(0, &persistent_origin));
248 const auto& fake_subscriber_it =
249 fake_watcher_.subscribers.find(GURL(persistent_origin));
250 ASSERT_NE(fake_watcher_.subscribers.end(), fake_subscriber_it);
251 EXPECT_TRUE(fake_subscriber_it->second.persistent);
252 }
253
TEST_F(FileSystemProviderRegistryTest,ForgetFileSystem)254 TEST_F(FileSystemProviderRegistryTest, ForgetFileSystem) {
255 // Create a fake file systems in the preferences.
256 RememberFakeFileSystem(profile_, kProviderId, kFileSystemId, kDisplayName,
257 true /* writable */, true /* supports_notify_tag */,
258 kOpenedFilesLimit, fake_watcher_);
259
260 registry_->ForgetFileSystem(kProviderId, kFileSystemId);
261
262 sync_preferences::TestingPrefServiceSyncable* const pref_service =
263 profile_->GetTestingPrefService();
264 ASSERT_TRUE(pref_service);
265
266 const base::DictionaryValue* const extensions =
267 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
268 ASSERT_TRUE(extensions);
269
270 const base::DictionaryValue* file_systems = NULL;
271 EXPECT_FALSE(extensions->GetDictionaryWithoutPathExpansion(
272 kProviderId.GetExtensionId(), &file_systems));
273 }
274
TEST_F(FileSystemProviderRegistryTest,UpdateWatcherTag)275 TEST_F(FileSystemProviderRegistryTest, UpdateWatcherTag) {
276 MountOptions options(kFileSystemId, kDisplayName);
277 options.writable = true;
278 options.supports_notify_tag = true;
279
280 ProvidedFileSystemInfo file_system_info(
281 kProviderId, options, base::FilePath(FILE_PATH_LITERAL("/a/b/c")),
282 false /* configurable */, true /* watchable */, extensions::SOURCE_FILE,
283 IconSet());
284
285 Watchers watchers;
286 watchers[WatcherKey(fake_watcher_.entry_path, fake_watcher_.recursive)] =
287 fake_watcher_;
288
289 registry_->RememberFileSystem(file_system_info, watchers);
290
291 fake_watcher_.last_tag = "updated-tag";
292 registry_->UpdateWatcherTag(file_system_info, fake_watcher_);
293
294 sync_preferences::TestingPrefServiceSyncable* const pref_service =
295 profile_->GetTestingPrefService();
296 ASSERT_TRUE(pref_service);
297
298 const base::DictionaryValue* const extensions =
299 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
300 ASSERT_TRUE(extensions);
301
302 const base::DictionaryValue* file_systems = NULL;
303 ASSERT_TRUE(extensions->GetDictionaryWithoutPathExpansion(
304 kProviderId.ToString(), &file_systems));
305 EXPECT_EQ(1u, file_systems->size());
306
307 const base::Value* file_system_value = NULL;
308 const base::DictionaryValue* file_system = NULL;
309 ASSERT_TRUE(
310 file_systems->GetWithoutPathExpansion(kFileSystemId, &file_system_value));
311 ASSERT_TRUE(file_system_value->GetAsDictionary(&file_system));
312
313 const base::DictionaryValue* watchers_value = NULL;
314 ASSERT_TRUE(file_system->GetDictionaryWithoutPathExpansion(kPrefKeyWatchers,
315 &watchers_value));
316
317 const base::DictionaryValue* watcher = NULL;
318 ASSERT_TRUE(watchers_value->GetDictionaryWithoutPathExpansion(
319 fake_watcher_.entry_path.value(), &watcher));
320
321 std::string last_tag;
322 EXPECT_TRUE(watcher->GetStringWithoutPathExpansion(kPrefKeyWatcherLastTag,
323 &last_tag));
324 EXPECT_EQ(fake_watcher_.last_tag, last_tag);
325 }
326
327 } // namespace file_system_provider
328 } // namespace chromeos
329