blob: 7dae077aaa4122ef5e50ddec5657d6b4c972ad96 [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001// 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"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010013#include "base/values.h"
14#include "chrome/browser/extensions/extension_apitest.h"
15#include "chrome/browser/extensions/extension_function_test_utils.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010016#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"
Torne (Richard Coles)90dce4d2013-05-29 14:40:03 +010022#include "webkit/browser/fileapi/external_mount_points.h"
23#include "webkit/common/fileapi/file_system_types.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010024
25namespace utils = extension_function_test_utils;
26
27using content::BrowserContext;
28using extensions::Extension;
29
30namespace {
31
32// Data that defines FileSelector behaviour in each test case.
33struct 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.
59void 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.
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010070class MockFileSelector : public file_manager::FileSelector {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010071 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
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +010083 // file_manager::FileSelector implementation.
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010084 // |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.
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100127class MockFileSelectorFactory : public file_manager::FileSelectorFactory {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100128 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
Torne (Richard Coles)a36e5922013-08-05 13:57:33 +0100137 // file_manager::FileSelectorFactory implementation.
138 virtual file_manager::FileSelector* CreateFileSelector() const OVERRIDE {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100139 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.
159class 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.
Ben Murdocheb525c52013-07-10 11:40:50 +0100165 ASSERT_TRUE(scoped_tmp_dir_.CreateUniqueTempDir());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100166 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_);
Ben Murdochbb1529c2013-08-08 10:24:53 +0100191 EXPECT_TRUE(!test_cases_ || current_test_case_ < test_cases_->size());
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100192
193 // If this happens, test failed. But, we still don't want to crash, so
194 // return valid extension function.
Ben Murdochbb1529c2013-08-08 10:24:53 +0100195 if (!test_cases_ || current_test_case_ >= test_cases_->size())
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100196 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
226const std::vector<TestCase>* FileBrowserHandlerExtensionTest::test_cases_ =
227 NULL;
228size_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.
238IN_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.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100267 ASSERT_FALSE(base::PathExists(selected_path));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100268
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.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100284 ASSERT_TRUE(base::PathExists(selected_path));
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100285
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.
300IN_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.
320IN_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).
349IN_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