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