| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/bind.h" |
| #include "base/file_util.h" |
| #include "base/files/file_path.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/chromeos/drive/drive_integration_service.h" |
| #include "chrome/browser/chromeos/extensions/file_manager/drive_test_util.h" |
| #include "chrome/browser/drive/fake_drive_service.h" |
| #include "chrome/browser/extensions/extension_apitest.h" |
| #include "chrome/browser/google_apis/test_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/test/test_utils.h" |
| #include "webkit/browser/fileapi/external_mount_points.h" |
| |
| // Tests for access to external file systems (as defined in |
| // webkit/common/fileapi/file_system_types.h) from extensions with |
| // fileBrowserPrivate and fileBrowserHandler extension permissions. |
| // The tests cover following external file system types: |
| // - local (kFileSystemTypeLocalNative): a local file system on which files are |
| // accessed using native local path. |
| // - restricted (kFileSystemTypeRestrictedLocalNative): a *read-only* local file |
| // system which can only be accessed by extensions that have full access to |
| // external file systems (i.e. extensions with fileBrowserPrivate permission). |
| // - drive (kFileSystemTypeDrive): a file system that provides access to Google |
| // Drive. |
| // |
| // The tests cover following scenarios: |
| // - Performing file system operations on external file systems from an |
| // extension with fileBrowserPrivate permission (i.e. a file browser |
| // extension). |
| // - Performing read/write operations from file handler extensions. These |
| // extensions need a file browser extension to give them permissions to access |
| // files. This also includes file handler extensions in filesystem API. |
| // - Observing directory changes from a file browser extension (using |
| // fileBrowserPrivate API). |
| // - Doing searches on drive file system from file browser extension (using |
| // fileBrowserPrivate API). |
| |
| using extensions::Extension; |
| |
| namespace file_manager { |
| namespace { |
| |
| // Root dirs for file systems expected by the test extensions. |
| // NOTE: Root dir for drive file system is set by Chrome's drive implementation, |
| // but the test will have to make sure the mount point is added before |
| // starting a test extension using WaitUntilDriveMountPointIsAdded(). |
| const char kLocalMountPointName[] = "local"; |
| const char kRestrictedMountPointName[] = "restricted"; |
| |
| // Default file content for the test files. |
| const char kTestFileContent[] = "This is some test content."; |
| |
| // Contains feed for drive file system. The file system hierarchy is the same |
| // for local and restricted file systems: |
| // test_dir/ - - subdir/ |
| // | |
| // - empty_test_dir/ |
| // | |
| // - empty_test_file.foo |
| // | |
| // - test_file.xul |
| // | |
| // - test_file.xul.foo |
| // | |
| // - test_file.tiff |
| // | |
| // - test_file.tiff.foo |
| // |
| // All files except test_dir/empty_file.foo, which is empty, initially contain |
| // kTestFileContent. |
| const char kTestRootFeed[] = |
| "gdata/remote_file_system_apitest_root_feed.json"; |
| |
| // Sets up the initial file system state for native local and restricted native |
| // local file systems. The hierarchy is the same as for the drive file system. |
| bool InitializeLocalFileSystem(base::ScopedTempDir* tmp_dir, |
| base::FilePath* mount_point_dir) { |
| if (!tmp_dir->CreateUniqueTempDir()) |
| return false; |
| |
| *mount_point_dir = tmp_dir->path().AppendASCII("mount"); |
| // Create the mount point. |
| if (!file_util::CreateDirectory(*mount_point_dir)) |
| return false; |
| |
| base::FilePath test_dir = mount_point_dir->AppendASCII("test_dir"); |
| if (!file_util::CreateDirectory(test_dir)) |
| return false; |
| |
| base::FilePath test_subdir = test_dir.AppendASCII("empty_test_dir"); |
| if (!file_util::CreateDirectory(test_subdir)) |
| return false; |
| |
| test_subdir = test_dir.AppendASCII("subdir"); |
| if (!file_util::CreateDirectory(test_subdir)) |
| return false; |
| |
| base::FilePath test_file = test_dir.AppendASCII("test_file.xul"); |
| if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent)) |
| return false; |
| |
| test_file = test_dir.AppendASCII("test_file.xul.foo"); |
| if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent)) |
| return false; |
| |
| test_file = test_dir.AppendASCII("test_file.tiff"); |
| if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent)) |
| return false; |
| |
| test_file = test_dir.AppendASCII("test_file.tiff.foo"); |
| if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent)) |
| return false; |
| |
| test_file = test_dir.AppendASCII("empty_test_file.foo"); |
| if (!google_apis::test_util::WriteStringToFile(test_file, "")) |
| return false; |
| |
| return true; |
| } |
| |
| // Helper class to wait for a background page to load or close again. |
| class BackgroundObserver { |
| public: |
| BackgroundObserver() |
| : page_created_(chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, |
| content::NotificationService::AllSources()), |
| page_closed_(chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, |
| content::NotificationService::AllSources()) { |
| } |
| |
| void WaitUntilLoaded() { |
| page_created_.Wait(); |
| } |
| |
| void WaitUntilClosed() { |
| page_closed_.Wait(); |
| } |
| |
| private: |
| content::WindowedNotificationObserver page_created_; |
| content::WindowedNotificationObserver page_closed_; |
| }; |
| |
| // Base class for FileSystemExtensionApi tests. |
| class FileSystemExtensionApiTestBase : public ExtensionApiTest { |
| public: |
| enum Flags { |
| FLAGS_NONE = 0, |
| FLAGS_USE_FILE_HANDLER = 1 << 1, |
| FLAGS_LAZY_FILE_HANDLER = 1 << 2 |
| }; |
| |
| FileSystemExtensionApiTestBase() {} |
| virtual ~FileSystemExtensionApiTestBase() {} |
| |
| virtual void SetUp() OVERRIDE { |
| InitTestFileSystem(); |
| ExtensionApiTest::SetUp(); |
| } |
| |
| virtual void SetUpOnMainThread() OVERRIDE { |
| AddTestMountPoint(); |
| ExtensionApiTest::SetUpOnMainThread(); |
| } |
| |
| // Runs a file system extension API test. |
| // It loads test component extension at |filebrowser_path| with manifest |
| // at |filebrowser_manifest|. The |filebrowser_manifest| should be a path |
| // relative to |filebrowser_path|. The method waits until the test extension |
| // sends test succeed or fail message. It returns true if the test succeeds. |
| // If |FLAGS_USE_FILE_HANDLER| flag is set, the file handler extension at path |
| // |filehandler_path| will be loaded before the file browser extension. |
| // If the flag FLAGS_LAZY_FILE_HANDLER is set, the file handler extension must |
| // not have persistent background page. The test will wait until the file |
| // handler's background page is closed after initial load before the file |
| // browser extension is loaded. |
| // If |RunFileSystemExtensionApiTest| fails, |message_| will contain a failure |
| // message. |
| bool RunFileSystemExtensionApiTest( |
| const std::string& filebrowser_path, |
| const base::FilePath::CharType* filebrowser_manifest, |
| const std::string& filehandler_path, |
| int flags) { |
| if (flags & FLAGS_USE_FILE_HANDLER) { |
| if (filehandler_path.empty()) { |
| message_ = "Missing file handler path."; |
| return false; |
| } |
| |
| BackgroundObserver page_complete; |
| const Extension* file_handler = |
| LoadExtension(test_data_dir_.AppendASCII(filehandler_path)); |
| if (!file_handler) |
| return false; |
| |
| if (flags & FLAGS_LAZY_FILE_HANDLER) { |
| page_complete.WaitUntilClosed(); |
| } else { |
| page_complete.WaitUntilLoaded(); |
| } |
| } |
| |
| ResultCatcher catcher; |
| |
| const Extension* file_browser = LoadExtensionAsComponentWithManifest( |
| test_data_dir_.AppendASCII(filebrowser_path), |
| filebrowser_manifest); |
| if (!file_browser) |
| return false; |
| |
| if (!catcher.GetNextResult()) { |
| message_ = catcher.message(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| protected: |
| // Sets up initial test file system hierarchy. See comment for kTestRootFeed |
| // for the actual hierarchy. |
| virtual void InitTestFileSystem() = 0; |
| // Registers mount point used in the test. |
| virtual void AddTestMountPoint() = 0; |
| }; |
| |
| // Tests for a native local file system. |
| class LocalFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase { |
| public: |
| LocalFileSystemExtensionApiTest() {} |
| virtual ~LocalFileSystemExtensionApiTest() {} |
| |
| // FileSystemExtensionApiTestBase OVERRIDE. |
| virtual void InitTestFileSystem() OVERRIDE { |
| ASSERT_TRUE(InitializeLocalFileSystem(&tmp_dir_, &mount_point_dir_)) |
| << "Failed to initialize file system."; |
| } |
| |
| // FileSystemExtensionApiTestBase OVERRIDE. |
| virtual void AddTestMountPoint() OVERRIDE { |
| EXPECT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile())-> |
| RegisterFileSystem(kLocalMountPointName, |
| fileapi::kFileSystemTypeNativeLocal, |
| mount_point_dir_)); |
| } |
| |
| private: |
| base::ScopedTempDir tmp_dir_; |
| base::FilePath mount_point_dir_; |
| }; |
| |
| // Tests for restricted native local file systems. |
| class RestrictedFileSystemExtensionApiTest |
| : public FileSystemExtensionApiTestBase { |
| public: |
| RestrictedFileSystemExtensionApiTest() {} |
| virtual ~RestrictedFileSystemExtensionApiTest() {} |
| |
| // FileSystemExtensionApiTestBase OVERRIDE. |
| virtual void InitTestFileSystem() OVERRIDE { |
| ASSERT_TRUE(InitializeLocalFileSystem(&tmp_dir_, &mount_point_dir_)) |
| << "Failed to initialize file system."; |
| } |
| |
| // FileSystemExtensionApiTestBase OVERRIDE. |
| virtual void AddTestMountPoint() OVERRIDE { |
| EXPECT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile())-> |
| RegisterFileSystem(kRestrictedMountPointName, |
| fileapi::kFileSystemTypeRestrictedNativeLocal, |
| mount_point_dir_)); |
| } |
| |
| private: |
| base::ScopedTempDir tmp_dir_; |
| base::FilePath mount_point_dir_; |
| }; |
| |
| // Tests for a drive file system. |
| class DriveFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase { |
| public: |
| DriveFileSystemExtensionApiTest() : fake_drive_service_(NULL) {} |
| virtual ~DriveFileSystemExtensionApiTest() {} |
| |
| // FileSystemExtensionApiTestBase OVERRIDE. |
| virtual void InitTestFileSystem() OVERRIDE { |
| // Set up cache root to be used by DriveIntegrationService. This has to be |
| // done before the browser is created because the service instance is |
| // initialized by EventRouter. |
| ASSERT_TRUE(test_cache_root_.CreateUniqueTempDir()); |
| |
| drive::DriveIntegrationServiceFactory::SetFactoryForTest( |
| base::Bind( |
| &DriveFileSystemExtensionApiTest::CreateDriveIntegrationService, |
| base::Unretained(this))); |
| } |
| |
| // FileSystemExtensionApiTestBase OVERRIDE. |
| virtual void AddTestMountPoint() OVERRIDE { |
| test_util::WaitUntilDriveMountPointIsAdded(browser()->profile()); |
| } |
| |
| protected: |
| // DriveIntegrationService factory function for this test. |
| drive::DriveIntegrationService* CreateDriveIntegrationService( |
| Profile* profile) { |
| fake_drive_service_ = new drive::FakeDriveService; |
| fake_drive_service_->LoadResourceListForWapi(kTestRootFeed); |
| fake_drive_service_->LoadAccountMetadataForWapi( |
| "gdata/account_metadata.json"); |
| fake_drive_service_->LoadAppListForDriveApi("drive/applist.json"); |
| |
| return new drive::DriveIntegrationService(profile, |
| fake_drive_service_, |
| test_cache_root_.path(), |
| NULL); |
| } |
| |
| base::ScopedTempDir test_cache_root_; |
| drive::FakeDriveService* fake_drive_service_; |
| }; |
| |
| // |
| // LocalFileSystemExtensionApiTests. |
| // |
| |
| IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileSystemOperations) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/filesystem_operations_test", |
| FILE_PATH_LITERAL("manifest.json"), |
| "", |
| FLAGS_NONE)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileWatch) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/file_watcher_test", |
| FILE_PATH_LITERAL("manifest.json"), |
| "", |
| FLAGS_NONE)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileBrowserHandlers) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/handler_test_runner", |
| FILE_PATH_LITERAL("manifest.json"), |
| "file_browser/file_browser_handler", |
| FLAGS_USE_FILE_HANDLER)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, |
| FileBrowserHandlersLazy) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/handler_test_runner", |
| FILE_PATH_LITERAL("manifest.json"), |
| "file_browser/file_browser_handler_lazy", |
| FLAGS_USE_FILE_HANDLER | FLAGS_LAZY_FILE_HANDLER)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, AppFileHandler) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/handler_test_runner", |
| FILE_PATH_LITERAL("manifest.json"), |
| "file_browser/app_file_handler", |
| FLAGS_USE_FILE_HANDLER)) << message_; |
| } |
| |
| // |
| // RestrictedFileSystemExtensionApiTests. |
| // |
| IN_PROC_BROWSER_TEST_F(RestrictedFileSystemExtensionApiTest, |
| FileSystemOperations) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/filesystem_operations_test", |
| FILE_PATH_LITERAL("manifest.json"), |
| "", |
| FLAGS_NONE)) << message_; |
| } |
| |
| // |
| // DriveFileSystemExtensionApiTests. |
| // |
| IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileSystemOperations) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/filesystem_operations_test", |
| FILE_PATH_LITERAL("manifest.json"), |
| "", |
| FLAGS_NONE)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileWatch) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/file_watcher_test", |
| FILE_PATH_LITERAL("manifest.json"), |
| "", |
| FLAGS_NONE)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileBrowserHandlers) { |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/handler_test_runner", |
| FILE_PATH_LITERAL("manifest.json"), |
| "file_browser/file_browser_handler", |
| FLAGS_USE_FILE_HANDLER)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, Search) { |
| // Configure the drive service to return only one search result at a time |
| // to simulate paginated searches. |
| fake_drive_service_->set_default_max_results(1); |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/drive_search_test", |
| FILE_PATH_LITERAL("manifest.json"), |
| "", |
| FLAGS_NONE)) << message_; |
| } |
| |
| IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, AppFileHandler) { |
| fake_drive_service_->set_default_max_results(1); |
| EXPECT_TRUE(RunFileSystemExtensionApiTest( |
| "file_browser/handler_test_runner", |
| FILE_PATH_LITERAL("manifest.json"), |
| "file_browser/app_file_handler", |
| FLAGS_USE_FILE_HANDLER)) << message_; |
| } |
| |
| } // namespace |
| } // namespace file_manager |