Home | History | Annotate | Download | only in file_manager
      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 "base/bind.h"
      6 #include "base/file_util.h"
      7 #include "base/files/file_path.h"
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "chrome/browser/chrome_notification_types.h"
     10 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
     11 #include "chrome/browser/chromeos/extensions/file_manager/drive_test_util.h"
     12 #include "chrome/browser/drive/fake_drive_service.h"
     13 #include "chrome/browser/extensions/extension_apitest.h"
     14 #include "chrome/browser/google_apis/test_util.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/ui/browser.h"
     17 #include "content/public/browser/browser_context.h"
     18 #include "content/public/browser/notification_service.h"
     19 #include "content/public/test/test_utils.h"
     20 #include "webkit/browser/fileapi/external_mount_points.h"
     21 
     22 // Tests for access to external file systems (as defined in
     23 // webkit/common/fileapi/file_system_types.h) from extensions with
     24 // fileBrowserPrivate and fileBrowserHandler extension permissions.
     25 // The tests cover following external file system types:
     26 // - local (kFileSystemTypeLocalNative): a local file system on which files are
     27 //   accessed using native local path.
     28 // - restricted (kFileSystemTypeRestrictedLocalNative): a *read-only* local file
     29 //   system which can only be accessed by extensions that have full access to
     30 //   external file systems (i.e. extensions with fileBrowserPrivate permission).
     31 // - drive (kFileSystemTypeDrive): a file system that provides access to Google
     32 //   Drive.
     33 //
     34 // The tests cover following scenarios:
     35 // - Performing file system operations on external file systems from an
     36 //   extension with fileBrowserPrivate permission (i.e. a file browser
     37 //   extension).
     38 // - Performing read/write operations from file handler extensions. These
     39 //   extensions need a file browser extension to give them permissions to access
     40 //   files. This also includes file handler extensions in filesystem API.
     41 // - Observing directory changes from a file browser extension (using
     42 //   fileBrowserPrivate API).
     43 // - Doing searches on drive file system from file browser extension (using
     44 //   fileBrowserPrivate API).
     45 
     46 using extensions::Extension;
     47 
     48 namespace file_manager {
     49 namespace {
     50 
     51 // Root dirs for file systems expected by the test extensions.
     52 // NOTE: Root dir for drive file system is set by Chrome's drive implementation,
     53 // but the test will have to make sure the mount point is added before
     54 // starting a test extension using WaitUntilDriveMountPointIsAdded().
     55 const char kLocalMountPointName[] = "local";
     56 const char kRestrictedMountPointName[] = "restricted";
     57 
     58 // Default file content for the test files.
     59 const char kTestFileContent[] = "This is some test content.";
     60 
     61 // Contains feed for drive file system. The file system hierarchy is the same
     62 // for local and restricted file systems:
     63 //   test_dir/ - - subdir/
     64 //              |
     65 //               - empty_test_dir/
     66 //              |
     67 //               - empty_test_file.foo
     68 //              |
     69 //               - test_file.xul
     70 //              |
     71 //               - test_file.xul.foo
     72 //              |
     73 //               - test_file.tiff
     74 //              |
     75 //               - test_file.tiff.foo
     76 //
     77 // All files except test_dir/empty_file.foo, which is empty, initially contain
     78 // kTestFileContent.
     79 const char kTestRootFeed[] =
     80     "gdata/remote_file_system_apitest_root_feed.json";
     81 
     82 // Sets up the initial file system state for native local and restricted native
     83 // local file systems. The hierarchy is the same as for the drive file system.
     84 bool InitializeLocalFileSystem(base::ScopedTempDir* tmp_dir,
     85                                base::FilePath* mount_point_dir) {
     86   if (!tmp_dir->CreateUniqueTempDir())
     87     return false;
     88 
     89   *mount_point_dir = tmp_dir->path().AppendASCII("mount");
     90   // Create the mount point.
     91   if (!file_util::CreateDirectory(*mount_point_dir))
     92     return false;
     93 
     94   base::FilePath test_dir = mount_point_dir->AppendASCII("test_dir");
     95   if (!file_util::CreateDirectory(test_dir))
     96     return false;
     97 
     98   base::FilePath test_subdir = test_dir.AppendASCII("empty_test_dir");
     99   if (!file_util::CreateDirectory(test_subdir))
    100     return false;
    101 
    102   test_subdir = test_dir.AppendASCII("subdir");
    103   if (!file_util::CreateDirectory(test_subdir))
    104     return false;
    105 
    106   base::FilePath test_file = test_dir.AppendASCII("test_file.xul");
    107   if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
    108     return false;
    109 
    110   test_file = test_dir.AppendASCII("test_file.xul.foo");
    111   if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
    112     return false;
    113 
    114   test_file = test_dir.AppendASCII("test_file.tiff");
    115   if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
    116     return false;
    117 
    118   test_file = test_dir.AppendASCII("test_file.tiff.foo");
    119   if (!google_apis::test_util::WriteStringToFile(test_file, kTestFileContent))
    120     return false;
    121 
    122   test_file = test_dir.AppendASCII("empty_test_file.foo");
    123   if (!google_apis::test_util::WriteStringToFile(test_file, ""))
    124     return false;
    125 
    126   return true;
    127 }
    128 
    129 // Helper class to wait for a background page to load or close again.
    130 class BackgroundObserver {
    131  public:
    132   BackgroundObserver()
    133       : page_created_(chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
    134                       content::NotificationService::AllSources()),
    135         page_closed_(chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
    136                      content::NotificationService::AllSources()) {
    137   }
    138 
    139   void WaitUntilLoaded() {
    140     page_created_.Wait();
    141   }
    142 
    143   void WaitUntilClosed() {
    144     page_closed_.Wait();
    145   }
    146 
    147  private:
    148   content::WindowedNotificationObserver page_created_;
    149   content::WindowedNotificationObserver page_closed_;
    150 };
    151 
    152 // Base class for FileSystemExtensionApi tests.
    153 class FileSystemExtensionApiTestBase : public ExtensionApiTest {
    154  public:
    155   enum Flags {
    156     FLAGS_NONE = 0,
    157     FLAGS_USE_FILE_HANDLER = 1 << 1,
    158     FLAGS_LAZY_FILE_HANDLER = 1 << 2
    159   };
    160 
    161   FileSystemExtensionApiTestBase() {}
    162   virtual ~FileSystemExtensionApiTestBase() {}
    163 
    164   virtual void SetUp() OVERRIDE {
    165     InitTestFileSystem();
    166     ExtensionApiTest::SetUp();
    167   }
    168 
    169   virtual void SetUpOnMainThread() OVERRIDE {
    170     AddTestMountPoint();
    171     ExtensionApiTest::SetUpOnMainThread();
    172   }
    173 
    174   // Runs a file system extension API test.
    175   // It loads test component extension at |filebrowser_path| with manifest
    176   // at |filebrowser_manifest|. The |filebrowser_manifest| should be a path
    177   // relative to |filebrowser_path|. The method waits until the test extension
    178   // sends test succeed or fail message. It returns true if the test succeeds.
    179   // If |FLAGS_USE_FILE_HANDLER| flag is set, the file handler extension at path
    180   // |filehandler_path| will be loaded before the file browser extension.
    181   // If the flag FLAGS_LAZY_FILE_HANDLER is set, the file handler extension must
    182   // not have persistent background page. The test will wait until the file
    183   // handler's background page is closed after initial load before the file
    184   // browser extension is loaded.
    185   // If |RunFileSystemExtensionApiTest| fails, |message_| will contain a failure
    186   // message.
    187   bool RunFileSystemExtensionApiTest(
    188       const std::string& filebrowser_path,
    189       const base::FilePath::CharType* filebrowser_manifest,
    190       const std::string& filehandler_path,
    191       int flags) {
    192     if (flags & FLAGS_USE_FILE_HANDLER) {
    193       if (filehandler_path.empty()) {
    194         message_ = "Missing file handler path.";
    195         return false;
    196       }
    197 
    198       BackgroundObserver page_complete;
    199       const Extension* file_handler =
    200           LoadExtension(test_data_dir_.AppendASCII(filehandler_path));
    201       if (!file_handler)
    202         return false;
    203 
    204       if (flags & FLAGS_LAZY_FILE_HANDLER) {
    205         page_complete.WaitUntilClosed();
    206       } else {
    207         page_complete.WaitUntilLoaded();
    208       }
    209     }
    210 
    211     ResultCatcher catcher;
    212 
    213     const Extension* file_browser = LoadExtensionAsComponentWithManifest(
    214         test_data_dir_.AppendASCII(filebrowser_path),
    215         filebrowser_manifest);
    216     if (!file_browser)
    217       return false;
    218 
    219     if (!catcher.GetNextResult()) {
    220       message_ = catcher.message();
    221       return false;
    222     }
    223 
    224     return true;
    225   }
    226 
    227  protected:
    228   // Sets up initial test file system hierarchy. See comment for kTestRootFeed
    229   // for the actual hierarchy.
    230   virtual void InitTestFileSystem() = 0;
    231   // Registers mount point used in the test.
    232   virtual void AddTestMountPoint() = 0;
    233 };
    234 
    235 // Tests for a native local file system.
    236 class LocalFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase {
    237  public:
    238   LocalFileSystemExtensionApiTest() {}
    239   virtual ~LocalFileSystemExtensionApiTest() {}
    240 
    241   // FileSystemExtensionApiTestBase OVERRIDE.
    242   virtual void InitTestFileSystem() OVERRIDE {
    243     ASSERT_TRUE(InitializeLocalFileSystem(&tmp_dir_, &mount_point_dir_))
    244         << "Failed to initialize file system.";
    245   }
    246 
    247   // FileSystemExtensionApiTestBase OVERRIDE.
    248   virtual void AddTestMountPoint() OVERRIDE {
    249     EXPECT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile())->
    250         RegisterFileSystem(kLocalMountPointName,
    251                            fileapi::kFileSystemTypeNativeLocal,
    252                            mount_point_dir_));
    253   }
    254 
    255  private:
    256   base::ScopedTempDir tmp_dir_;
    257   base::FilePath mount_point_dir_;
    258 };
    259 
    260 // Tests for restricted native local file systems.
    261 class RestrictedFileSystemExtensionApiTest
    262     : public FileSystemExtensionApiTestBase {
    263  public:
    264   RestrictedFileSystemExtensionApiTest() {}
    265   virtual ~RestrictedFileSystemExtensionApiTest() {}
    266 
    267   // FileSystemExtensionApiTestBase OVERRIDE.
    268   virtual void InitTestFileSystem() OVERRIDE {
    269     ASSERT_TRUE(InitializeLocalFileSystem(&tmp_dir_, &mount_point_dir_))
    270         << "Failed to initialize file system.";
    271   }
    272 
    273   // FileSystemExtensionApiTestBase OVERRIDE.
    274   virtual void AddTestMountPoint() OVERRIDE {
    275     EXPECT_TRUE(content::BrowserContext::GetMountPoints(browser()->profile())->
    276         RegisterFileSystem(kRestrictedMountPointName,
    277                            fileapi::kFileSystemTypeRestrictedNativeLocal,
    278                            mount_point_dir_));
    279   }
    280 
    281  private:
    282   base::ScopedTempDir tmp_dir_;
    283   base::FilePath mount_point_dir_;
    284 };
    285 
    286 // Tests for a drive file system.
    287 class DriveFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase {
    288  public:
    289   DriveFileSystemExtensionApiTest() : fake_drive_service_(NULL) {}
    290   virtual ~DriveFileSystemExtensionApiTest() {}
    291 
    292   // FileSystemExtensionApiTestBase OVERRIDE.
    293   virtual void InitTestFileSystem() OVERRIDE {
    294     // Set up cache root to be used by DriveIntegrationService. This has to be
    295     // done before the browser is created because the service instance is
    296     // initialized by EventRouter.
    297     ASSERT_TRUE(test_cache_root_.CreateUniqueTempDir());
    298 
    299     drive::DriveIntegrationServiceFactory::SetFactoryForTest(
    300         base::Bind(
    301             &DriveFileSystemExtensionApiTest::CreateDriveIntegrationService,
    302             base::Unretained(this)));
    303   }
    304 
    305   // FileSystemExtensionApiTestBase OVERRIDE.
    306   virtual void AddTestMountPoint() OVERRIDE {
    307     test_util::WaitUntilDriveMountPointIsAdded(browser()->profile());
    308   }
    309 
    310  protected:
    311   // DriveIntegrationService factory function for this test.
    312   drive::DriveIntegrationService* CreateDriveIntegrationService(
    313       Profile* profile) {
    314     fake_drive_service_ = new drive::FakeDriveService;
    315     fake_drive_service_->LoadResourceListForWapi(kTestRootFeed);
    316     fake_drive_service_->LoadAccountMetadataForWapi(
    317         "gdata/account_metadata.json");
    318     fake_drive_service_->LoadAppListForDriveApi("drive/applist.json");
    319 
    320     return new drive::DriveIntegrationService(profile,
    321                                               fake_drive_service_,
    322                                               test_cache_root_.path(),
    323                                               NULL);
    324   }
    325 
    326   base::ScopedTempDir test_cache_root_;
    327   drive::FakeDriveService* fake_drive_service_;
    328 };
    329 
    330 //
    331 // LocalFileSystemExtensionApiTests.
    332 //
    333 
    334 IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileSystemOperations) {
    335   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    336       "file_browser/filesystem_operations_test",
    337       FILE_PATH_LITERAL("manifest.json"),
    338       "",
    339       FLAGS_NONE)) << message_;
    340 }
    341 
    342 IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileWatch) {
    343   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    344       "file_browser/file_watcher_test",
    345       FILE_PATH_LITERAL("manifest.json"),
    346       "",
    347       FLAGS_NONE)) << message_;
    348 }
    349 
    350 IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileBrowserHandlers) {
    351   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    352       "file_browser/handler_test_runner",
    353       FILE_PATH_LITERAL("manifest.json"),
    354       "file_browser/file_browser_handler",
    355       FLAGS_USE_FILE_HANDLER)) << message_;
    356 }
    357 
    358 IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest,
    359                        FileBrowserHandlersLazy) {
    360   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    361       "file_browser/handler_test_runner",
    362       FILE_PATH_LITERAL("manifest.json"),
    363       "file_browser/file_browser_handler_lazy",
    364       FLAGS_USE_FILE_HANDLER | FLAGS_LAZY_FILE_HANDLER)) << message_;
    365 }
    366 
    367 IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, AppFileHandler) {
    368   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    369       "file_browser/handler_test_runner",
    370       FILE_PATH_LITERAL("manifest.json"),
    371       "file_browser/app_file_handler",
    372       FLAGS_USE_FILE_HANDLER)) << message_;
    373 }
    374 
    375 //
    376 // RestrictedFileSystemExtensionApiTests.
    377 //
    378 IN_PROC_BROWSER_TEST_F(RestrictedFileSystemExtensionApiTest,
    379                        FileSystemOperations) {
    380   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    381       "file_browser/filesystem_operations_test",
    382       FILE_PATH_LITERAL("manifest.json"),
    383       "",
    384       FLAGS_NONE)) << message_;
    385 }
    386 
    387 //
    388 // DriveFileSystemExtensionApiTests.
    389 //
    390 IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileSystemOperations) {
    391   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    392       "file_browser/filesystem_operations_test",
    393       FILE_PATH_LITERAL("manifest.json"),
    394       "",
    395       FLAGS_NONE)) << message_;
    396 }
    397 
    398 IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileWatch) {
    399   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    400       "file_browser/file_watcher_test",
    401       FILE_PATH_LITERAL("manifest.json"),
    402       "",
    403       FLAGS_NONE)) << message_;
    404 }
    405 
    406 IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileBrowserHandlers) {
    407   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    408       "file_browser/handler_test_runner",
    409       FILE_PATH_LITERAL("manifest.json"),
    410       "file_browser/file_browser_handler",
    411       FLAGS_USE_FILE_HANDLER)) << message_;
    412 }
    413 
    414 IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, Search) {
    415   // Configure the drive service to return only one search result at a time
    416   // to simulate paginated searches.
    417   fake_drive_service_->set_default_max_results(1);
    418   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    419       "file_browser/drive_search_test",
    420       FILE_PATH_LITERAL("manifest.json"),
    421       "",
    422       FLAGS_NONE)) << message_;
    423 }
    424 
    425 IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, AppFileHandler) {
    426   fake_drive_service_->set_default_max_results(1);
    427   EXPECT_TRUE(RunFileSystemExtensionApiTest(
    428       "file_browser/handler_test_runner",
    429       FILE_PATH_LITERAL("manifest.json"),
    430       "file_browser/app_file_handler",
    431       FLAGS_USE_FILE_HANDLER)) << message_;
    432 }
    433 
    434 }  // namespace
    435 }  // namespace file_manager
    436