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 // File contains browser tests for the fileBrowserHandler api.
      6 
      7 #include "chrome/browser/chromeos/extensions/file_manager/file_browser_handler_api.h"
      8 
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/values.h"
     14 #include "chrome/browser/extensions/extension_apitest.h"
     15 #include "chrome/browser/extensions/extension_function_test_utils.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/ui/browser.h"
     18 #include "chrome/common/extensions/extension.h"
     19 #include "chrome/test/base/in_process_browser_test.h"
     20 #include "chrome/test/base/ui_test_utils.h"
     21 #include "content/public/browser/browser_context.h"
     22 #include "webkit/browser/fileapi/external_mount_points.h"
     23 #include "webkit/common/fileapi/file_system_types.h"
     24 
     25 namespace utils = extension_function_test_utils;
     26 
     27 using content::BrowserContext;
     28 using extensions::Extension;
     29 
     30 namespace {
     31 
     32 // Data that defines FileSelector behaviour in each test case.
     33 struct TestCase {
     34   TestCase(const base::FilePath& suggested_name,
     35            const std::vector<std::string>& allowed_extensions,
     36            bool success,
     37            const base::FilePath& selected_path)
     38       : suggested_name(suggested_name),
     39         allowed_extensions(allowed_extensions),
     40         success(success),
     41         selected_path(selected_path) {
     42   }
     43   ~TestCase() {}
     44 
     45   // Path that we expect to be suggested to the file selector.
     46   base::FilePath suggested_name;
     47 
     48   // Extensions that we expect to be allowed to the file selector.
     49   std::vector<std::string> allowed_extensions;
     50 
     51   // Whether file selector should fail.
     52   bool success;
     53   // The path file selector should return back to the function.
     54   base::FilePath selected_path;
     55 };
     56 
     57 // Checks that file under path |selected_path| contains |expected_contents|.
     58 // Must be called on the file thread.
     59 void ExpectFileContentEquals(const base::FilePath& selected_path,
     60                              const std::string& expected_contents) {
     61   std::string test_file_contents;
     62   ASSERT_TRUE(file_util::ReadFileToString(selected_path, &test_file_contents));
     63   EXPECT_EQ(expected_contents, test_file_contents);
     64 }
     65 
     66 // Mocks FileSelector used by FileBrowserHandlerInternalSelectFileFunction.
     67 // When |SelectFile| is called, it will check that file name suggestion is as
     68 // expected, and respond to the extension function with specified selection
     69 // results.
     70 class MockFileSelector : public file_manager::FileSelector {
     71  public:
     72   MockFileSelector(const base::FilePath& suggested_name,
     73                    const std::vector<std::string>& allowed_extensions,
     74                    bool success,
     75                    const base::FilePath& selected_path)
     76       : suggested_name_(suggested_name),
     77         allowed_extensions_(allowed_extensions),
     78         success_(success),
     79         selected_path_(selected_path) {
     80   }
     81   virtual ~MockFileSelector() {}
     82 
     83   // file_manager::FileSelector implementation.
     84   // |browser| is not used.
     85   virtual void SelectFile(
     86       const base::FilePath& suggested_name,
     87       const std::vector<std::string>& allowed_extensions,
     88       Browser* browser,
     89       FileBrowserHandlerInternalSelectFileFunction* function) OVERRIDE {
     90     // Confirm that the function suggested us the right name.
     91     EXPECT_EQ(suggested_name_, suggested_name);
     92     // Confirm that the function allowed us the right extensions.
     93     EXPECT_EQ(allowed_extensions_.size(), allowed_extensions.size());
     94     if (allowed_extensions_.size() == allowed_extensions.size()) {
     95       for (size_t i = 0; i < allowed_extensions_.size(); ++i) {
     96         EXPECT_EQ(allowed_extensions_[i], allowed_extensions[i]);
     97       }
     98     }
     99 
    100     // Send response to the extension function.
    101     // The callback will take a reference to the function and keep it alive.
    102     base::MessageLoopProxy::current()->PostTask(FROM_HERE,
    103         base::Bind(&FileBrowserHandlerInternalSelectFileFunction::
    104                        OnFilePathSelected,
    105                    function, success_, selected_path_));
    106     delete this;
    107   }
    108 
    109  private:
    110   // File name that is expected to be suggested by the function.
    111   base::FilePath suggested_name_;
    112 
    113   // Extensions that is expected to be allowed by the function.
    114   std::vector<std::string> allowed_extensions_;
    115 
    116   // Whether the selection should succeed.
    117   bool success_;
    118   // File path that should be returned to the function.
    119   base::FilePath selected_path_;
    120 
    121   DISALLOW_COPY_AND_ASSIGN(MockFileSelector);
    122 };
    123 
    124 // Mocks file selector factory for the test.
    125 // When |CreateFileSelector| is invoked it will create mock file selector for
    126 // the extension function with test parameters from the object ctor.
    127 class MockFileSelectorFactory : public file_manager::FileSelectorFactory {
    128  public:
    129   explicit MockFileSelectorFactory(const TestCase& test_case)
    130       : suggested_name_(test_case.suggested_name),
    131         allowed_extensions_(test_case.allowed_extensions),
    132         success_(test_case.success),
    133         selected_path_(test_case.selected_path) {
    134   }
    135   virtual ~MockFileSelectorFactory() {}
    136 
    137   // file_manager::FileSelectorFactory implementation.
    138   virtual file_manager::FileSelector* CreateFileSelector() const OVERRIDE {
    139     return new MockFileSelector(suggested_name_,
    140                                 allowed_extensions_,
    141                                 success_,
    142                                 selected_path_);
    143   }
    144 
    145  private:
    146   // File name that is expected to be suggested by the function.
    147   base::FilePath suggested_name_;
    148   // Extensions that is expected to be allowed by the function.
    149   std::vector<std::string> allowed_extensions_;
    150   // Whether the selection should succeed.
    151   bool success_;
    152   // File path that should be returned to the function.
    153   base::FilePath selected_path_;
    154 
    155   DISALLOW_COPY_AND_ASSIGN(MockFileSelectorFactory);
    156 };
    157 
    158 // Extension api test for the fileBrowserHandler extension API.
    159 class FileBrowserHandlerExtensionTest : public ExtensionApiTest {
    160  protected:
    161   virtual void SetUp() OVERRIDE {
    162     // Create mount point directory that will be used in the test.
    163     // Mount point will be called "tmp", and it will be located in a tmp
    164     // directory with an unique name.
    165     ASSERT_TRUE(scoped_tmp_dir_.CreateUniqueTempDir());
    166     tmp_mount_point_ = scoped_tmp_dir_.path().Append("tmp");
    167     file_util::CreateDirectory(tmp_mount_point_);
    168 
    169     ExtensionApiTest::SetUp();
    170   }
    171 
    172   // Creates new, test mount point.
    173   void AddTmpMountPoint(const std::string& extension_id) {
    174     BrowserContext::GetMountPoints(browser()->profile())->RegisterFileSystem(
    175         "tmp",
    176         fileapi::kFileSystemTypeNativeLocal,
    177         tmp_mount_point_);
    178   }
    179 
    180   base::FilePath GetFullPathOnTmpMountPoint(
    181       const base::FilePath& relative_path) {
    182     return tmp_mount_point_.Append(relative_path);
    183   }
    184 
    185   // Creates a new FileBrowserHandlerInternalSelectFileFunction to be used in
    186   // the test.  This function will be called from ExtensionFunctinoDispatcher
    187   // whenever an extension function for fileBrowserHandlerInternal.selectFile
    188   // will be needed.
    189   static ExtensionFunction* TestSelectFileFunctionFactory() {
    190     EXPECT_TRUE(test_cases_);
    191     EXPECT_TRUE(!test_cases_ || current_test_case_ < test_cases_->size());
    192 
    193     // If this happens, test failed. But, we still don't want to crash, so
    194     // return valid extension function.
    195     if (!test_cases_ || current_test_case_ >= test_cases_->size())
    196       return new FileBrowserHandlerInternalSelectFileFunction();
    197 
    198     // Create file creator factory for the current test case.
    199     MockFileSelectorFactory* mock_factory =
    200         new MockFileSelectorFactory(test_cases_->at(current_test_case_));
    201     current_test_case_++;
    202 
    203     return new FileBrowserHandlerInternalSelectFileFunction(
    204         mock_factory, false);
    205   }
    206 
    207   // Sets up test parameters for extension function invocations that will be
    208   // made during the test.
    209   void SetTestCases(const std::vector<TestCase>* test_cases) {
    210     test_cases_ = test_cases;
    211     current_test_case_ = 0;
    212   }
    213 
    214  private:
    215   // List of test parameters for each extension function invocation that will be
    216   // made during a test.
    217   // Should be owned by the test code.
    218   static const std::vector<TestCase>* test_cases_;
    219   static size_t current_test_case_;
    220 
    221   base::ScopedTempDir scoped_tmp_dir_;
    222   // Our test mount point path.
    223   base::FilePath tmp_mount_point_;
    224 };
    225 
    226 const std::vector<TestCase>* FileBrowserHandlerExtensionTest::test_cases_ =
    227     NULL;
    228 size_t FileBrowserHandlerExtensionTest::current_test_case_ = 0;
    229 
    230 // End to end test that verifies that fileBrowserHandler.selectFile works as
    231 // expected. It will run test extension under
    232 // chrome/test/data/extensions/api_test/file_browser/filehandler_create.
    233 // The extension will invoke fileBrowserHandler.selectFile function twice.
    234 // Once with suggested name "some_file_name.txt", and once with suggested name
    235 // "fail". The file selection should succeed the first time, but fail the second
    236 // time. When the file is selected the test extension will verify that it can
    237 // create, read and write the file under the selected file path.
    238 IN_PROC_BROWSER_TEST_F(FileBrowserHandlerExtensionTest, EndToEnd) {
    239   // Path that will be "selected" by file selector.
    240   const base::FilePath selected_path =
    241       GetFullPathOnTmpMountPoint(base::FilePath("test_file.txt"));
    242 
    243   std::vector<std::string> allowed_extensions;
    244   allowed_extensions.push_back("txt");
    245   allowed_extensions.push_back("html");
    246 
    247   std::vector<TestCase> test_cases;
    248   test_cases.push_back(
    249       TestCase(base::FilePath("some_file_name.txt"),
    250                allowed_extensions,
    251                true,
    252                selected_path));
    253   test_cases.push_back(
    254       TestCase(base::FilePath("fail"),
    255                std::vector<std::string>(),
    256                false,
    257                base::FilePath()));
    258 
    259   SetTestCases(&test_cases);
    260 
    261   // Override extension function that will be used during the test.
    262   ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction(
    263       "fileBrowserHandlerInternal.selectFile",
    264       FileBrowserHandlerExtensionTest::TestSelectFileFunctionFactory));
    265 
    266   // Selected path should still not exist.
    267   ASSERT_FALSE(base::PathExists(selected_path));
    268 
    269   const Extension* extension = LoadExtension(
    270       test_data_dir_.AppendASCII("file_browser/filehandler_create"));
    271   ASSERT_TRUE(extension) << message_;
    272 
    273   AddTmpMountPoint(extension->id());
    274 
    275   ResultCatcher catcher;
    276 
    277   GURL url = extension->GetResourceURL("test.html");
    278   ui_test_utils::NavigateToURL(browser(), url);
    279 
    280   ASSERT_TRUE(catcher.GetNextResult()) << message_;
    281 
    282   // Selected path should have been created by the test extension after the
    283   // extension function call.
    284   ASSERT_TRUE(base::PathExists(selected_path));
    285 
    286   // Let's check that the file has the expected content.
    287   const std::string expected_contents = "hello from test extension.";
    288   content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
    289       base::Bind(&ExpectFileContentEquals, selected_path, expected_contents));
    290 
    291   // Make sure test doesn't finish until we check on file thread that the
    292   // selected file's content is as expected.
    293   content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
    294 
    295   SetTestCases(NULL);
    296 }
    297 
    298 // Tests that verifies the fileBrowserHandlerInternal.selectFile function fails
    299 // when invoked without user gesture.
    300 IN_PROC_BROWSER_TEST_F(FileBrowserHandlerExtensionTest, NoUserGesture) {
    301   scoped_refptr<FileBrowserHandlerInternalSelectFileFunction>
    302       select_file_function(
    303           new FileBrowserHandlerInternalSelectFileFunction());
    304 
    305   std::string error =
    306       utils::RunFunctionAndReturnError(
    307           select_file_function.get(),
    308           "[{\"suggestedName\": \"foo\"}]",
    309           browser());
    310 
    311   const std::string expected_error =
    312       "This method can only be called in response to user gesture, such as a "
    313       "mouse click or key press.";
    314   EXPECT_EQ(expected_error, error);
    315 }
    316 
    317 // Tests that checks that the fileHandlerInternal.selectFile function returns
    318 // dictionary with |success == false| and no file entry when user cancels file
    319 // selection.
    320 IN_PROC_BROWSER_TEST_F(FileBrowserHandlerExtensionTest, SelectionFailed) {
    321   TestCase test_case(base::FilePath("some_file_name.txt"),
    322                      std::vector<std::string>(),
    323                      false,
    324                      base::FilePath());
    325 
    326   scoped_refptr<FileBrowserHandlerInternalSelectFileFunction>
    327       select_file_function(
    328           new FileBrowserHandlerInternalSelectFileFunction(
    329               new MockFileSelectorFactory(test_case),
    330               false));
    331 
    332   select_file_function->set_has_callback(true);
    333   select_file_function->set_user_gesture(true);
    334 
    335   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
    336       utils::RunFunctionAndReturnSingleResult(
    337           select_file_function.get(),
    338           "[{\"suggestedName\": \"some_file_name.txt\"}]",
    339           browser())));
    340 
    341   EXPECT_FALSE(utils::GetBoolean(result.get(), "success"));
    342   DictionaryValue* entry_info;
    343   EXPECT_FALSE(result->GetDictionary("entry", &entry_info));
    344 }
    345 
    346 // Tests that user cannot be suggested a full file path when selecting a file,
    347 // only a file name (i.e. that extension function caller has no influence on
    348 // which directory contents will be initially displayed in selection dialog).
    349 IN_PROC_BROWSER_TEST_F(FileBrowserHandlerExtensionTest, SuggestedFullPath) {
    350   TestCase test_case(base::FilePath("some_file_name.txt"),
    351                      std::vector<std::string>(),
    352                      false,
    353                      base::FilePath());
    354 
    355   scoped_refptr<FileBrowserHandlerInternalSelectFileFunction>
    356       select_file_function(
    357           new FileBrowserHandlerInternalSelectFileFunction(
    358               new MockFileSelectorFactory(test_case),
    359               false));
    360 
    361   select_file_function->set_has_callback(true);
    362   select_file_function->set_user_gesture(true);
    363 
    364   scoped_ptr<base::DictionaryValue> result(utils::ToDictionary(
    365       utils::RunFunctionAndReturnSingleResult(
    366           select_file_function.get(),
    367           "[{\"suggestedName\": \"/path_to_file/some_file_name.txt\"}]",
    368           browser())));
    369 
    370   EXPECT_FALSE(utils::GetBoolean(result.get(), "success"));
    371   DictionaryValue* entry_info;
    372   EXPECT_FALSE(result->GetDictionary("entry", &entry_info));
    373 }
    374 
    375 }  // namespace
    376