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.
5 #include "chrome/browser/chromeos/file_system_provider/service.h"
10 #include "base/files/file.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h"
15 #include "chrome/browser/chromeos/file_system_provider/mount_path_util.h"
16 #include "chrome/browser/chromeos/file_system_provider/observer.h"
17 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
18 #include "chrome/browser/chromeos/login/users/fake_user_manager.h"
19 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
20 #include "chrome/common/pref_names.h"
21 #include "chrome/test/base/testing_pref_service_syncable.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "components/user_prefs/user_prefs.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "extensions/browser/extension_registry.h"
26 #include "extensions/common/extension.h"
27 #include "extensions/common/manifest_constants.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29 #include "webkit/browser/fileapi/external_mount_points.h"
32 namespace file_system_provider {
35 const char kExtensionId[] = "mbflcebpggnecokmikipoihdbecnjfoj";
36 const char kDisplayName[] = "Camera Pictures";
38 // The dot in the file system ID is there in order to check that saving to
39 // preferences works correctly. File System ID is used as a key in
40 // a base::DictionaryValue, so it has to be stored without path expansion.
41 const char kFileSystemId[] = "camera/pictures/id .!@#$%^&*()_+";
43 // Utility observer, logging events from file_system_provider::Service.
44 class LoggingObserver : public Observer {
48 Event(const ProvidedFileSystemInfo& file_system_info,
49 base::File::Error error)
50 : file_system_info_(file_system_info), error_(error) {}
53 const ProvidedFileSystemInfo& file_system_info() {
54 return file_system_info_;
56 base::File::Error error() { return error_; }
59 ProvidedFileSystemInfo file_system_info_;
60 base::File::Error error_;
64 virtual ~LoggingObserver() {}
66 // file_system_provider::Observer overrides.
67 virtual void OnProvidedFileSystemMount(
68 const ProvidedFileSystemInfo& file_system_info,
69 base::File::Error error) OVERRIDE {
70 mounts.push_back(Event(file_system_info, error));
73 virtual void OnProvidedFileSystemUnmount(
74 const ProvidedFileSystemInfo& file_system_info,
75 base::File::Error error) OVERRIDE {
76 unmounts.push_back(Event(file_system_info, error));
79 std::vector<Event> mounts;
80 std::vector<Event> unmounts;
83 // Creates a fake extension with the specified |extension_id|.
84 scoped_refptr<extensions::Extension> createFakeExtension(
85 const std::string& extension_id) {
86 base::DictionaryValue manifest;
88 manifest.SetStringWithoutPathExpansion(extensions::manifest_keys::kVersion,
90 manifest.SetStringWithoutPathExpansion(extensions::manifest_keys::kName,
92 return extensions::Extension::Create(base::FilePath(),
93 extensions::Manifest::UNPACKED,
95 extensions::Extension::NO_FLAGS,
100 // Stores a provided file system information in preferences.
101 void RememberFakeFileSystem(TestingProfile* profile,
102 const std::string& extension_id,
103 const std::string& file_system_id,
104 const std::string& display_name,
106 TestingPrefServiceSyncable* const pref_service =
107 profile->GetTestingPrefService();
108 ASSERT_TRUE(pref_service);
110 base::DictionaryValue extensions;
111 base::DictionaryValue* file_systems = new base::DictionaryValue();
112 base::DictionaryValue* file_system = new base::DictionaryValue();
113 file_system->SetStringWithoutPathExpansion(kPrefKeyFileSystemId,
115 file_system->SetStringWithoutPathExpansion(kPrefKeyDisplayName, kDisplayName);
116 file_system->SetBooleanWithoutPathExpansion(kPrefKeyWritable, writable);
117 file_systems->SetWithoutPathExpansion(kFileSystemId, file_system);
118 extensions.SetWithoutPathExpansion(kExtensionId, file_systems);
120 pref_service->Set(prefs::kFileSystemProviderMounted, extensions);
125 class FileSystemProviderServiceTest : public testing::Test {
127 FileSystemProviderServiceTest() {}
128 virtual ~FileSystemProviderServiceTest() {}
130 virtual void SetUp() OVERRIDE {
131 profile_.reset(new TestingProfile);
132 user_manager_ = new FakeUserManager();
133 user_manager_->AddUser(profile_->GetProfileName());
134 user_manager_enabler_.reset(new ScopedUserManagerEnabler(user_manager_));
135 extension_registry_.reset(
136 new extensions::ExtensionRegistry(profile_.get()));
137 service_.reset(new Service(profile_.get(), extension_registry_.get()));
138 service_->SetFileSystemFactoryForTesting(
139 base::Bind(&FakeProvidedFileSystem::Create));
140 extension_ = createFakeExtension(kExtensionId);
143 content::TestBrowserThreadBundle thread_bundle_;
144 scoped_ptr<TestingProfile> profile_;
145 FakeUserManager* user_manager_;
146 scoped_ptr<ScopedUserManagerEnabler> user_manager_enabler_;
147 scoped_ptr<extensions::ExtensionRegistry> extension_registry_;
148 scoped_ptr<Service> service_;
149 scoped_refptr<extensions::Extension> extension_;
152 TEST_F(FileSystemProviderServiceTest, MountFileSystem) {
153 LoggingObserver observer;
154 service_->AddObserver(&observer);
156 EXPECT_TRUE(service_->MountFileSystem(
157 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
159 ASSERT_EQ(1u, observer.mounts.size());
160 EXPECT_EQ(kExtensionId, observer.mounts[0].file_system_info().extension_id());
161 EXPECT_EQ(kFileSystemId,
162 observer.mounts[0].file_system_info().file_system_id());
163 base::FilePath expected_mount_path =
164 util::GetMountPath(profile_.get(), kExtensionId, kFileSystemId);
165 EXPECT_EQ(expected_mount_path.AsUTF8Unsafe(),
166 observer.mounts[0].file_system_info().mount_path().AsUTF8Unsafe());
167 EXPECT_EQ(kDisplayName, observer.mounts[0].file_system_info().display_name());
168 EXPECT_FALSE(observer.mounts[0].file_system_info().writable());
169 EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
170 ASSERT_EQ(0u, observer.unmounts.size());
172 std::vector<ProvidedFileSystemInfo> file_system_info_list =
173 service_->GetProvidedFileSystemInfoList();
174 ASSERT_EQ(1u, file_system_info_list.size());
176 service_->RemoveObserver(&observer);
179 TEST_F(FileSystemProviderServiceTest, MountFileSystem_Writable) {
180 LoggingObserver observer;
181 service_->AddObserver(&observer);
183 EXPECT_TRUE(service_->MountFileSystem(
184 kExtensionId, kFileSystemId, kDisplayName, true /* writable */));
186 ASSERT_EQ(1u, observer.mounts.size());
187 EXPECT_TRUE(observer.mounts[0].file_system_info().writable());
188 ASSERT_EQ(0u, observer.unmounts.size());
189 std::vector<ProvidedFileSystemInfo> file_system_info_list =
190 service_->GetProvidedFileSystemInfoList();
191 ASSERT_EQ(1u, file_system_info_list.size());
193 service_->RemoveObserver(&observer);
196 TEST_F(FileSystemProviderServiceTest, MountFileSystem_UniqueIds) {
197 LoggingObserver observer;
198 service_->AddObserver(&observer);
200 EXPECT_TRUE(service_->MountFileSystem(
201 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
202 EXPECT_FALSE(service_->MountFileSystem(
203 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
205 ASSERT_EQ(2u, observer.mounts.size());
206 EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
207 EXPECT_EQ(base::File::FILE_ERROR_EXISTS, observer.mounts[1].error());
209 std::vector<ProvidedFileSystemInfo> file_system_info_list =
210 service_->GetProvidedFileSystemInfoList();
211 ASSERT_EQ(1u, file_system_info_list.size());
213 service_->RemoveObserver(&observer);
216 TEST_F(FileSystemProviderServiceTest, MountFileSystem_StressTest) {
217 LoggingObserver observer;
218 service_->AddObserver(&observer);
220 const size_t kMaxFileSystems = 16;
221 for (size_t i = 0; i < kMaxFileSystems; ++i) {
222 const std::string file_system_id =
223 std::string("test-") + base::IntToString(i);
224 EXPECT_TRUE(service_->MountFileSystem(
225 kExtensionId, file_system_id, kDisplayName, false /* writable */));
227 ASSERT_EQ(kMaxFileSystems, observer.mounts.size());
229 // The next file system is out of limit, and registering it should fail.
230 EXPECT_FALSE(service_->MountFileSystem(
231 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
233 ASSERT_EQ(kMaxFileSystems + 1, observer.mounts.size());
234 EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED,
235 observer.mounts[kMaxFileSystems].error());
237 std::vector<ProvidedFileSystemInfo> file_system_info_list =
238 service_->GetProvidedFileSystemInfoList();
239 ASSERT_EQ(kMaxFileSystems, file_system_info_list.size());
241 service_->RemoveObserver(&observer);
244 TEST_F(FileSystemProviderServiceTest, UnmountFileSystem) {
245 LoggingObserver observer;
246 service_->AddObserver(&observer);
248 EXPECT_TRUE(service_->MountFileSystem(
249 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
250 ASSERT_EQ(1u, observer.mounts.size());
252 EXPECT_TRUE(service_->UnmountFileSystem(
253 kExtensionId, kFileSystemId, Service::UNMOUNT_REASON_USER));
254 ASSERT_EQ(1u, observer.unmounts.size());
255 EXPECT_EQ(base::File::FILE_OK, observer.unmounts[0].error());
257 EXPECT_EQ(kExtensionId,
258 observer.unmounts[0].file_system_info().extension_id());
259 EXPECT_EQ(kFileSystemId,
260 observer.unmounts[0].file_system_info().file_system_id());
262 std::vector<ProvidedFileSystemInfo> file_system_info_list =
263 service_->GetProvidedFileSystemInfoList();
264 ASSERT_EQ(0u, file_system_info_list.size());
266 service_->RemoveObserver(&observer);
269 TEST_F(FileSystemProviderServiceTest, UnmountFileSystem_OnExtensionUnload) {
270 LoggingObserver observer;
271 service_->AddObserver(&observer);
273 EXPECT_TRUE(service_->MountFileSystem(
274 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
275 ASSERT_EQ(1u, observer.mounts.size());
277 // Directly call the observer's method.
278 service_->OnExtensionUnloaded(
281 extensions::UnloadedExtensionInfo::REASON_DISABLE);
283 ASSERT_EQ(1u, observer.unmounts.size());
284 EXPECT_EQ(base::File::FILE_OK, observer.unmounts[0].error());
286 EXPECT_EQ(kExtensionId,
287 observer.unmounts[0].file_system_info().extension_id());
288 EXPECT_EQ(kFileSystemId,
289 observer.unmounts[0].file_system_info().file_system_id());
291 std::vector<ProvidedFileSystemInfo> file_system_info_list =
292 service_->GetProvidedFileSystemInfoList();
293 ASSERT_EQ(0u, file_system_info_list.size());
295 service_->RemoveObserver(&observer);
298 TEST_F(FileSystemProviderServiceTest, UnmountFileSystem_WrongExtensionId) {
299 LoggingObserver observer;
300 service_->AddObserver(&observer);
302 const std::string kWrongExtensionId = "helloworldhelloworldhelloworldhe";
304 EXPECT_TRUE(service_->MountFileSystem(
305 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
306 ASSERT_EQ(1u, observer.mounts.size());
307 ASSERT_EQ(1u, service_->GetProvidedFileSystemInfoList().size());
309 EXPECT_FALSE(service_->UnmountFileSystem(
310 kWrongExtensionId, kFileSystemId, Service::UNMOUNT_REASON_USER));
311 ASSERT_EQ(1u, observer.unmounts.size());
312 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, observer.unmounts[0].error());
313 ASSERT_EQ(1u, service_->GetProvidedFileSystemInfoList().size());
315 std::vector<ProvidedFileSystemInfo> file_system_info_list =
316 service_->GetProvidedFileSystemInfoList();
317 ASSERT_EQ(1u, file_system_info_list.size());
319 service_->RemoveObserver(&observer);
322 TEST_F(FileSystemProviderServiceTest, RestoreFileSystem_OnExtensionLoad) {
323 // Create a fake entry in the preferences.
324 RememberFakeFileSystem(profile_.get(),
328 true /* writable */);
330 // Create a new service instance in order to load remembered file systems
332 scoped_ptr<Service> new_service(
333 new Service(profile_.get(), extension_registry_.get()));
334 LoggingObserver observer;
335 new_service->AddObserver(&observer);
337 new_service->SetFileSystemFactoryForTesting(
338 base::Bind(&FakeProvidedFileSystem::Create));
340 EXPECT_EQ(0u, observer.mounts.size());
342 // Directly call the observer's method.
343 new_service->OnExtensionLoaded(profile_.get(), extension_.get());
345 ASSERT_EQ(1u, observer.mounts.size());
346 EXPECT_EQ(base::File::FILE_OK, observer.mounts[0].error());
348 EXPECT_EQ(kExtensionId, observer.mounts[0].file_system_info().extension_id());
349 EXPECT_EQ(kFileSystemId,
350 observer.mounts[0].file_system_info().file_system_id());
351 EXPECT_TRUE(observer.mounts[0].file_system_info().writable());
353 std::vector<ProvidedFileSystemInfo> file_system_info_list =
354 new_service->GetProvidedFileSystemInfoList();
355 ASSERT_EQ(1u, file_system_info_list.size());
357 new_service->RemoveObserver(&observer);
360 TEST_F(FileSystemProviderServiceTest, RememberFileSystem_OnMount) {
361 LoggingObserver observer;
362 service_->AddObserver(&observer);
364 EXPECT_TRUE(service_->MountFileSystem(
365 kExtensionId, kFileSystemId, kDisplayName, true /* writable */));
366 ASSERT_EQ(1u, observer.mounts.size());
368 TestingPrefServiceSyncable* const pref_service =
369 profile_->GetTestingPrefService();
370 ASSERT_TRUE(pref_service);
372 const base::DictionaryValue* const extensions =
373 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
374 ASSERT_TRUE(extensions);
376 const base::DictionaryValue* file_systems = NULL;
377 ASSERT_TRUE(extensions->GetDictionaryWithoutPathExpansion(kExtensionId,
379 EXPECT_EQ(1u, file_systems->size());
381 const base::Value* file_system_value = NULL;
382 const base::DictionaryValue* file_system = NULL;
384 file_systems->GetWithoutPathExpansion(kFileSystemId, &file_system_value));
385 ASSERT_TRUE(file_system_value->GetAsDictionary(&file_system));
387 std::string file_system_id;
388 EXPECT_TRUE(file_system->GetStringWithoutPathExpansion(kPrefKeyFileSystemId,
390 EXPECT_EQ(kFileSystemId, file_system_id);
392 std::string display_name;
393 EXPECT_TRUE(file_system->GetStringWithoutPathExpansion(kPrefKeyDisplayName,
395 EXPECT_EQ(kDisplayName, display_name);
397 bool writable = false;
399 file_system->GetBooleanWithoutPathExpansion(kPrefKeyWritable, &writable));
400 EXPECT_TRUE(writable);
402 service_->RemoveObserver(&observer);
405 TEST_F(FileSystemProviderServiceTest, RememberFileSystem_OnUnmountOnShutdown) {
406 LoggingObserver observer;
407 service_->AddObserver(&observer);
409 TestingPrefServiceSyncable* const pref_service =
410 profile_->GetTestingPrefService();
411 ASSERT_TRUE(pref_service);
414 EXPECT_TRUE(service_->MountFileSystem(
415 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
416 ASSERT_EQ(1u, observer.mounts.size());
418 const base::DictionaryValue* extensions =
419 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
420 ASSERT_TRUE(extensions);
422 const base::DictionaryValue* file_systems = NULL;
423 ASSERT_TRUE(extensions->GetDictionaryWithoutPathExpansion(kExtensionId,
425 EXPECT_EQ(1u, file_systems->size());
429 EXPECT_TRUE(service_->UnmountFileSystem(
430 kExtensionId, kFileSystemId, Service::UNMOUNT_REASON_SHUTDOWN));
432 const base::DictionaryValue* const extensions =
433 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
434 ASSERT_TRUE(extensions);
436 const base::DictionaryValue* file_systems = NULL;
437 ASSERT_TRUE(extensions->GetDictionaryWithoutPathExpansion(kExtensionId,
439 EXPECT_EQ(1u, file_systems->size());
442 service_->RemoveObserver(&observer);
445 TEST_F(FileSystemProviderServiceTest, RememberFileSystem_OnUnmountByUser) {
446 LoggingObserver observer;
447 service_->AddObserver(&observer);
449 TestingPrefServiceSyncable* const pref_service =
450 profile_->GetTestingPrefService();
451 ASSERT_TRUE(pref_service);
454 EXPECT_TRUE(service_->MountFileSystem(
455 kExtensionId, kFileSystemId, kDisplayName, false /* writable */));
456 ASSERT_EQ(1u, observer.mounts.size());
458 const base::DictionaryValue* extensions =
459 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
460 ASSERT_TRUE(extensions);
462 const base::DictionaryValue* file_systems = NULL;
463 ASSERT_TRUE(extensions->GetDictionaryWithoutPathExpansion(kExtensionId,
465 EXPECT_EQ(1u, file_systems->size());
469 EXPECT_TRUE(service_->UnmountFileSystem(
470 kExtensionId, kFileSystemId, Service::UNMOUNT_REASON_USER));
472 const base::DictionaryValue* const extensions =
473 pref_service->GetDictionary(prefs::kFileSystemProviderMounted);
474 ASSERT_TRUE(extensions);
476 const base::DictionaryValue* file_systems = NULL;
477 EXPECT_FALSE(extensions->GetDictionaryWithoutPathExpansion(kExtensionId,
481 service_->RemoveObserver(&observer);
484 } // namespace file_system_provider
485 } // namespace chromeos