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/extensions/api/file_system/file_system_api.h"
7 #include "base/callback.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/location.h"
11 #include "base/path_service.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chrome/browser/apps/app_browsertest_util.h"
14 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
15 #include "chrome/browser/chromeos/drive/file_system_util.h"
16 #include "chrome/browser/chromeos/file_manager/volume_manager.h"
17 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
18 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
19 #include "chrome/browser/chromeos/profiles/profile_helper.h"
20 #include "chrome/browser/extensions/component_loader.h"
21 #include "chrome/common/chrome_paths.h"
22 #include "chrome/common/extensions/api/file_system.h"
23 #include "components/drive/file_system_interface.h"
24 #include "components/drive/service/fake_drive_service.h"
25 #include "content/public/test/test_utils.h"
26 #include "extensions/browser/event_router.h"
27 #include "google_apis/drive/drive_api_parser.h"
28 #include "google_apis/drive/test_util.h"
29 #include "storage/browser/fileapi/external_mount_points.h"
30 #include "ui/base/ui_base_types.h"
32 using file_manager::VolumeManager
;
34 namespace extensions
{
37 // Mount point names for chrome.fileSystem.requestFileSystem() tests.
38 const char kWritableMountPointName
[] = "writable";
39 const char kReadOnlyMountPointName
[] = "read-only";
41 // Child directory created in each of the mount points.
42 const char kChildDirectory
[] = "child-dir";
44 // ID of a testing extension.
45 const char kTestingExtensionId
[] = "pkplfbidichfdicaijlchgnapepdginl";
49 // Skips the user consent dialog for chrome.fileSystem.requestFileSystem() and
50 // simulates clicking of the specified dialog button.
51 class ScopedSkipRequestFileSystemDialog
{
53 explicit ScopedSkipRequestFileSystemDialog(ui::DialogButton button
) {
54 file_system_api::ConsentProviderDelegate::SetAutoDialogButtonForTest(
57 ~ScopedSkipRequestFileSystemDialog() {
58 file_system_api::ConsentProviderDelegate::SetAutoDialogButtonForTest(
59 ui::DIALOG_BUTTON_NONE
);
63 DISALLOW_COPY_AND_ASSIGN(ScopedSkipRequestFileSystemDialog
);
66 // Observers adding a listener to the |event_name| event by |extension|, and
67 // then fires the |callback|.
68 class ScopedAddListenerObserver
: public EventRouter::Observer
{
70 ScopedAddListenerObserver(Profile
* profile
,
71 const std::string
& event_name
,
72 const std::string
& extension_id
,
73 const base::Closure
& callback
)
74 : extension_id_(extension_id
),
76 event_router_(EventRouter::EventRouter::Get(profile
)) {
78 DCHECK(event_router_
);
79 event_router_
->RegisterObserver(this, event_name
);
82 ~ScopedAddListenerObserver() { event_router_
->UnregisterObserver(this); }
84 // EventRouter::Observer overrides.
85 void OnListenerAdded(const EventListenerInfo
& details
) override
{
86 // Call the callback only once, as the listener may be added multiple times.
87 if (details
.extension_id
== extension_id_
&& !callback_
.is_null()) {
88 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE
, callback_
);
89 callback_
= base::Closure();
94 const std::string extension_id_
;
95 base::Closure callback_
;
96 EventRouter
* const event_router_
;
98 DISALLOW_COPY_AND_ASSIGN(ScopedAddListenerObserver
);
101 // This class contains chrome.filesystem API test specific to Chrome OS, namely,
102 // the integrated Google Drive support.
103 class FileSystemApiTestForDrive
: public PlatformAppBrowserTest
{
105 FileSystemApiTestForDrive()
106 : fake_drive_service_(NULL
),
107 integration_service_(NULL
) {
110 // Sets up fake Drive service for tests (this has to be injected before the
111 // real DriveIntegrationService instance is created.)
112 void SetUpInProcessBrowserTestFixture() override
{
113 PlatformAppBrowserTest::SetUpInProcessBrowserTestFixture();
114 extensions::ComponentLoader::EnableBackgroundExtensionsForTesting();
116 ASSERT_TRUE(test_cache_root_
.CreateUniqueTempDir());
118 create_drive_integration_service_
=
119 base::Bind(&FileSystemApiTestForDrive::CreateDriveIntegrationService
,
120 base::Unretained(this));
121 service_factory_for_test_
.reset(
122 new drive::DriveIntegrationServiceFactory::ScopedFactoryForTest(
123 &create_drive_integration_service_
));
126 // Ensure the fake service's data is fetch in the local file system. This is
127 // necessary because the fetch starts lazily upon the first read operation.
128 void SetUpOnMainThread() override
{
129 PlatformAppBrowserTest::SetUpOnMainThread();
131 scoped_ptr
<drive::ResourceEntry
> entry
;
132 drive::FileError error
= drive::FILE_ERROR_FAILED
;
133 integration_service_
->file_system()->GetResourceEntry(
134 base::FilePath::FromUTF8Unsafe("drive/root"), // whatever
135 google_apis::test_util::CreateCopyResultCallback(&error
, &entry
));
136 content::RunAllBlockingPoolTasksUntilIdle();
137 ASSERT_EQ(drive::FILE_ERROR_OK
, error
);
140 void TearDown() override
{
141 FileSystemChooseEntryFunction::StopSkippingPickerForTest();
142 PlatformAppBrowserTest::TearDown();
146 drive::DriveIntegrationService
* CreateDriveIntegrationService(
148 // Ignore signin profile.
149 if (profile
->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir())
152 // FileSystemApiTestForDrive doesn't expect that several user profiles could
153 // exist simultaneously.
154 DCHECK(fake_drive_service_
== NULL
);
155 fake_drive_service_
= new drive::FakeDriveService
;
156 fake_drive_service_
->LoadAppListForDriveApi("drive/applist.json");
158 SetUpTestFileHierarchy();
160 integration_service_
= new drive::DriveIntegrationService(
161 profile
, NULL
, fake_drive_service_
, std::string(),
162 test_cache_root_
.path(), NULL
);
163 return integration_service_
;
166 void SetUpTestFileHierarchy() {
167 const std::string root
= fake_drive_service_
->GetRootResourceId();
168 ASSERT_TRUE(AddTestFile("open_existing.txt", "Can you see me?", root
));
169 ASSERT_TRUE(AddTestFile("open_existing1.txt", "Can you see me?", root
));
170 ASSERT_TRUE(AddTestFile("open_existing2.txt", "Can you see me?", root
));
171 ASSERT_TRUE(AddTestFile("save_existing.txt", "Can you see me?", root
));
172 const std::string subdir
= AddTestDirectory("subdir", root
);
173 ASSERT_FALSE(subdir
.empty());
174 ASSERT_TRUE(AddTestFile("open_existing.txt", "Can you see me?", subdir
));
177 bool AddTestFile(const std::string
& title
,
178 const std::string
& data
,
179 const std::string
& parent_id
) {
180 scoped_ptr
<google_apis::FileResource
> entry
;
181 google_apis::DriveApiErrorCode error
= google_apis::DRIVE_OTHER_ERROR
;
182 fake_drive_service_
->AddNewFile(
183 "text/plain", data
, parent_id
, title
, false,
184 google_apis::test_util::CreateCopyResultCallback(&error
, &entry
));
185 content::RunAllPendingInMessageLoop();
186 return error
== google_apis::HTTP_CREATED
&& entry
;
189 std::string
AddTestDirectory(const std::string
& title
,
190 const std::string
& parent_id
) {
191 scoped_ptr
<google_apis::FileResource
> entry
;
192 google_apis::DriveApiErrorCode error
= google_apis::DRIVE_OTHER_ERROR
;
193 fake_drive_service_
->AddNewDirectory(
194 parent_id
, title
, drive::AddNewDirectoryOptions(),
195 google_apis::test_util::CreateCopyResultCallback(&error
, &entry
));
196 content::RunAllPendingInMessageLoop();
197 return error
== google_apis::HTTP_CREATED
&& entry
? entry
->file_id() : "";
200 base::ScopedTempDir test_cache_root_
;
201 drive::FakeDriveService
* fake_drive_service_
;
202 drive::DriveIntegrationService
* integration_service_
;
203 drive::DriveIntegrationServiceFactory::FactoryCallback
204 create_drive_integration_service_
;
205 scoped_ptr
<drive::DriveIntegrationServiceFactory::ScopedFactoryForTest
>
206 service_factory_for_test_
;
209 // This class contains chrome.filesystem.requestFileSystem API tests.
210 class FileSystemApiTestForRequestFileSystem
: public PlatformAppBrowserTest
{
212 FileSystemApiTestForRequestFileSystem() : fake_user_manager_(nullptr) {}
214 void SetUpOnMainThread() override
{
215 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
216 CreateTestingFileSystem(kWritableMountPointName
, false /* read_only */);
217 CreateTestingFileSystem(kReadOnlyMountPointName
, true /* read_only */);
218 PlatformAppBrowserTest::SetUpOnMainThread();
221 void TearDownOnMainThread() override
{
222 PlatformAppBrowserTest::TearDownOnMainThread();
223 user_manager_enabler_
.reset();
224 fake_user_manager_
= nullptr;
227 // Simulates mounting a removable volume.
228 void MountFakeVolume() {
229 VolumeManager
* const volume_manager
=
230 VolumeManager::Get(browser()->profile());
231 ASSERT_TRUE(volume_manager
);
232 volume_manager
->AddVolumeForTesting(
233 base::FilePath("/a/b/c"), file_manager::VOLUME_TYPE_TESTING
,
234 chromeos::DEVICE_TYPE_UNKNOWN
, false /* read_only */);
238 base::ScopedTempDir temp_dir_
;
239 chromeos::FakeChromeUserManager
* fake_user_manager_
;
240 scoped_ptr
<chromeos::ScopedUserManagerEnabler
> user_manager_enabler_
;
242 // Creates a testing file system in a testing directory.
243 void CreateTestingFileSystem(const std::string
& mount_point_name
,
245 const base::FilePath mount_point_path
=
246 temp_dir_
.path().Append(mount_point_name
);
247 ASSERT_TRUE(base::CreateDirectory(mount_point_path
));
249 base::CreateDirectory(mount_point_path
.Append(kChildDirectory
)));
250 ASSERT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile())
251 ->RegisterFileSystem(
252 mount_point_name
, storage::kFileSystemTypeNativeLocal
,
253 storage::FileSystemMountOption(), mount_point_path
));
254 VolumeManager
* const volume_manager
=
255 VolumeManager::Get(browser()->profile());
256 ASSERT_TRUE(volume_manager
);
257 volume_manager
->AddVolumeForTesting(
258 mount_point_path
, file_manager::VOLUME_TYPE_TESTING
,
259 chromeos::DEVICE_TYPE_UNKNOWN
, read_only
);
262 // Simulates entering the kiosk session.
263 void EnterKioskSession() {
264 fake_user_manager_
= new chromeos::FakeChromeUserManager();
265 user_manager_enabler_
.reset(
266 new chromeos::ScopedUserManagerEnabler(fake_user_manager_
));
268 const std::string kKioskLogin
= "kiosk@foobar.com";
269 fake_user_manager_
->AddKioskAppUser(kKioskLogin
);
270 fake_user_manager_
->LoginUser(kKioskLogin
);
274 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
275 FileSystemApiOpenExistingFileTest
) {
276 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
277 browser()->profile()).AppendASCII("root/open_existing.txt");
278 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
280 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_existing"))
284 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
285 FileSystemApiOpenExistingFileWithWriteTest
) {
286 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
287 browser()->profile()).AppendASCII("root/open_existing.txt");
288 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
290 ASSERT_TRUE(RunPlatformAppTest(
291 "api_test/file_system/open_existing_with_write")) << message_
;
294 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
295 FileSystemApiOpenMultipleSuggested
) {
296 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
297 browser()->profile()).AppendASCII("root/open_existing.txt");
298 ASSERT_TRUE(PathService::OverrideAndCreateIfNeeded(
299 chrome::DIR_USER_DOCUMENTS
, test_file
.DirName(), true, false));
300 FileSystemChooseEntryFunction::SkipPickerAndSelectSuggestedPathForTest();
301 ASSERT_TRUE(RunPlatformAppTest(
302 "api_test/file_system/open_multiple_with_suggested_name"))
306 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
307 FileSystemApiOpenMultipleExistingFilesTest
) {
308 base::FilePath test_file1
= drive::util::GetDriveMountPointPath(
309 browser()->profile()).AppendASCII("root/open_existing1.txt");
310 base::FilePath test_file2
= drive::util::GetDriveMountPointPath(
311 browser()->profile()).AppendASCII("root/open_existing2.txt");
312 std::vector
<base::FilePath
> test_files
;
313 test_files
.push_back(test_file1
);
314 test_files
.push_back(test_file2
);
315 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathsForTest(
317 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_multiple_existing"))
321 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
322 FileSystemApiOpenDirectoryTest
) {
323 base::FilePath test_directory
=
324 drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII(
326 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
328 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/open_directory"))
332 #if defined(ADDRESS_SANITIZER)
333 // Flaky when run under ASan: crbug.com/499233.
334 #define MAYBE_FileSystemApiOpenDirectoryWithWriteTest \
335 DISABLED_FileSystemApiOpenDirectoryWithWriteTest
337 #define MAYBE_FileSystemApiOpenDirectoryWithWriteTest \
338 FileSystemApiOpenDirectoryWithWriteTest
340 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
341 MAYBE_FileSystemApiOpenDirectoryWithWriteTest
) {
342 base::FilePath test_directory
=
343 drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII(
345 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
348 RunPlatformAppTest("api_test/file_system/open_directory_with_write"))
352 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
353 FileSystemApiOpenDirectoryWithoutPermissionTest
) {
354 base::FilePath test_directory
=
355 drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII(
357 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
359 ASSERT_TRUE(RunPlatformAppTest(
360 "api_test/file_system/open_directory_without_permission"))
364 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
365 FileSystemApiOpenDirectoryWithOnlyWritePermissionTest
) {
366 base::FilePath test_directory
=
367 drive::util::GetDriveMountPointPath(browser()->profile()).AppendASCII(
369 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
371 ASSERT_TRUE(RunPlatformAppTest(
372 "api_test/file_system/open_directory_with_only_write"))
376 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
377 FileSystemApiSaveNewFileTest
) {
378 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
379 browser()->profile()).AppendASCII("root/save_new.txt");
380 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
382 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/save_new"))
386 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
387 FileSystemApiSaveExistingFileTest
) {
388 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
389 browser()->profile()).AppendASCII("root/save_existing.txt");
390 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
392 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/save_existing"))
396 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
397 FileSystemApiSaveNewFileWithWriteTest
) {
398 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
399 browser()->profile()).AppendASCII("root/save_new.txt");
400 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
402 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/save_new_with_write"))
406 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForDrive
,
407 FileSystemApiSaveExistingFileWithWriteTest
) {
408 base::FilePath test_file
= drive::util::GetDriveMountPointPath(
409 browser()->profile()).AppendASCII("root/save_existing.txt");
410 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
412 ASSERT_TRUE(RunPlatformAppTest(
413 "api_test/file_system/save_existing_with_write")) << message_
;
416 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
, Background
) {
418 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_OK
);
420 RunPlatformAppTest("api_test/file_system/request_file_system_background"))
424 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
, ReadOnly
) {
426 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_OK
);
428 RunPlatformAppTest("api_test/file_system/request_file_system_read_only"))
432 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
, Writable
) {
434 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_OK
);
436 RunPlatformAppTest("api_test/file_system/request_file_system_writable"))
440 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
, UserReject
) {
442 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_CANCEL
);
443 ASSERT_TRUE(RunPlatformAppTest(
444 "api_test/file_system/request_file_system_user_reject"))
448 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
, NotKioskSession
) {
449 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_OK
);
450 ASSERT_TRUE(RunPlatformAppTest(
451 "api_test/file_system/request_file_system_not_kiosk_session"))
455 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
,
456 WhitelistedComponent
) {
457 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_CANCEL
);
458 ASSERT_TRUE(RunPlatformAppTestWithFlags(
459 "api_test/file_system/request_file_system_whitelisted_component",
460 kFlagLoadAsComponent
))
464 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
,
465 NotWhitelistedComponent
) {
466 ScopedSkipRequestFileSystemDialog
dialog_skipper(ui::DIALOG_BUTTON_OK
);
467 ASSERT_TRUE(RunPlatformAppTestWithFlags(
468 "api_test/file_system/request_file_system_not_whitelisted_component",
469 kFlagLoadAsComponent
))
473 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
, GetVolumeList
) {
475 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/get_volume_list"))
479 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
,
480 GetVolumeList_NotKioskSession
) {
481 ASSERT_TRUE(RunPlatformAppTest(
482 "api_test/file_system/get_volume_list_not_kiosk_session"))
486 IN_PROC_BROWSER_TEST_F(FileSystemApiTestForRequestFileSystem
,
487 OnVolumeListChanged
) {
490 ScopedAddListenerObserver
observer(
491 profile(), extensions::api::file_system::OnVolumeListChanged::kEventName
,
493 base::Bind(&FileSystemApiTestForRequestFileSystem::MountFakeVolume
,
496 ASSERT_TRUE(RunPlatformAppTest("api_test/file_system/on_volume_list_changed"))
500 } // namespace extensions