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