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