Implement MoveFileLocal (with creating a snapshot).
[chromium-blink-merge.git] / chrome / browser / media_galleries / fileapi / native_media_file_util_unittest.cc
blobd1a48282f42f317b7b0cfa2a5fa751c3f592335e
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 #include <set>
6 #include <string>
8 #include "base/bind.h"
9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h"
11 #include "base/format_macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/time/time.h"
16 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
17 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
18 #include "content/public/test/mock_special_storage_policy.h"
19 #include "content/public/test/test_browser_thread.h"
20 #include "content/public/test/test_file_system_options.h"
21 #include "storage/browser/fileapi/external_mount_points.h"
22 #include "storage/browser/fileapi/file_system_backend.h"
23 #include "storage/browser/fileapi/file_system_context.h"
24 #include "storage/browser/fileapi/file_system_operation_runner.h"
25 #include "storage/browser/fileapi/file_system_url.h"
26 #include "storage/browser/fileapi/isolated_context.h"
27 #include "storage/browser/fileapi/native_file_util.h"
28 #include "testing/gtest/include/gtest/gtest.h"
30 #define FPL(x) FILE_PATH_LITERAL(x)
32 using storage::FileSystemOperation;
33 using storage::FileSystemURL;
35 namespace {
37 typedef FileSystemOperation::FileEntryList FileEntryList;
39 struct FilteringTestCase {
40 const base::FilePath::CharType* path;
41 bool is_directory;
42 bool visible;
43 bool media_file;
44 const char* content;
47 const FilteringTestCase kFilteringTestCases[] = {
48 // Directory should always be visible.
49 { FPL("hoge"), true, true, false, NULL },
50 { FPL("fuga.jpg"), true, true, false, NULL },
51 { FPL("piyo.txt"), true, true, false, NULL },
52 { FPL("moga.cod"), true, true, false, NULL },
54 // File should be visible if it's a supported media file.
55 // File without extension.
56 { FPL("foo"), false, false, false, "abc" },
57 // Supported media file.
58 { FPL("bar.jpg"), false, true, true, "\xFF\xD8\xFF" },
59 // Unsupported masquerading file.
60 { FPL("sna.jpg"), false, true, false, "abc" },
61 // Non-media file.
62 { FPL("baz.txt"), false, false, false, "abc" },
63 // Unsupported media file.
64 { FPL("foobar.cod"), false, false, false, "abc" },
67 void ExpectEqHelper(const std::string& test_name,
68 base::File::Error expected,
69 base::File::Error actual) {
70 EXPECT_EQ(expected, actual) << test_name;
73 void ExpectMetadataEqHelper(const std::string& test_name,
74 base::File::Error expected,
75 bool expected_is_directory,
76 base::File::Error actual,
77 const base::File::Info& file_info) {
78 EXPECT_EQ(expected, actual) << test_name;
79 if (actual == base::File::FILE_OK)
80 EXPECT_EQ(expected_is_directory, file_info.is_directory) << test_name;
83 void DidReadDirectory(std::set<base::FilePath::StringType>* content,
84 bool* completed,
85 base::File::Error error,
86 const FileEntryList& file_list,
87 bool has_more) {
88 EXPECT_TRUE(!*completed);
89 *completed = !has_more;
90 for (FileEntryList::const_iterator itr = file_list.begin();
91 itr != file_list.end(); ++itr)
92 EXPECT_TRUE(content->insert(itr->name).second);
95 void PopulateDirectoryWithTestCases(const base::FilePath& dir,
96 const FilteringTestCase* test_cases,
97 size_t n) {
98 for (size_t i = 0; i < n; ++i) {
99 base::FilePath path = dir.Append(test_cases[i].path);
100 if (test_cases[i].is_directory) {
101 ASSERT_TRUE(base::CreateDirectory(path));
102 } else {
103 ASSERT_TRUE(test_cases[i].content != NULL);
104 int len = strlen(test_cases[i].content);
105 ASSERT_EQ(len, base::WriteFile(path, test_cases[i].content, len));
110 } // namespace
112 class NativeMediaFileUtilTest : public testing::Test {
113 public:
114 NativeMediaFileUtilTest()
115 : io_thread_(content::BrowserThread::IO, &message_loop_) {
118 void SetUp() override {
119 ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
120 ASSERT_TRUE(base::CreateDirectory(root_path()));
122 scoped_refptr<storage::SpecialStoragePolicy> storage_policy =
123 new content::MockSpecialStoragePolicy();
125 ScopedVector<storage::FileSystemBackend> additional_providers;
126 additional_providers.push_back(new MediaFileSystemBackend(
127 data_dir_.path(), base::MessageLoopProxy::current().get()));
129 file_system_context_ = new storage::FileSystemContext(
130 base::MessageLoopProxy::current().get(),
131 base::MessageLoopProxy::current().get(),
132 storage::ExternalMountPoints::CreateRefCounted().get(),
133 storage_policy.get(),
134 NULL,
135 additional_providers.Pass(),
136 std::vector<storage::URLRequestAutoMountHandler>(),
137 data_dir_.path(),
138 content::CreateAllowFileAccessOptions());
140 filesystem_id_ = isolated_context()->RegisterFileSystemForPath(
141 storage::kFileSystemTypeNativeMedia, std::string(), root_path(), NULL);
143 isolated_context()->AddReference(filesystem_id_);
146 void TearDown() override {
147 isolated_context()->RemoveReference(filesystem_id_);
148 file_system_context_ = NULL;
151 protected:
152 storage::FileSystemContext* file_system_context() {
153 return file_system_context_.get();
156 FileSystemURL CreateURL(const base::FilePath::CharType* test_case_path) {
157 return file_system_context_->CreateCrackedFileSystemURL(
158 origin(),
159 storage::kFileSystemTypeIsolated,
160 GetVirtualPath(test_case_path));
163 storage::IsolatedContext* isolated_context() {
164 return storage::IsolatedContext::GetInstance();
167 base::FilePath root_path() {
168 return data_dir_.path().Append(FPL("Media Directory"));
171 base::FilePath GetVirtualPath(
172 const base::FilePath::CharType* test_case_path) {
173 return base::FilePath::FromUTF8Unsafe(filesystem_id_).
174 Append(FPL("Media Directory")).
175 Append(base::FilePath(test_case_path));
178 GURL origin() {
179 return GURL("http://example.com");
182 storage::FileSystemType type() { return storage::kFileSystemTypeNativeMedia; }
184 storage::FileSystemOperationRunner* operation_runner() {
185 return file_system_context_->operation_runner();
188 private:
189 base::MessageLoop message_loop_;
190 content::TestBrowserThread io_thread_;
192 base::ScopedTempDir data_dir_;
193 scoped_refptr<storage::FileSystemContext> file_system_context_;
195 std::string filesystem_id_;
197 DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtilTest);
200 TEST_F(NativeMediaFileUtilTest, DirectoryExistsAndFileExistsFiltering) {
201 PopulateDirectoryWithTestCases(root_path(),
202 kFilteringTestCases,
203 arraysize(kFilteringTestCases));
205 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
206 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
208 base::File::Error expectation =
209 kFilteringTestCases[i].visible ?
210 base::File::FILE_OK :
211 base::File::FILE_ERROR_NOT_FOUND;
213 std::string test_name =
214 base::StringPrintf("DirectoryExistsAndFileExistsFiltering %" PRIuS, i);
215 if (kFilteringTestCases[i].is_directory) {
216 operation_runner()->DirectoryExists(
217 url, base::Bind(&ExpectEqHelper, test_name, expectation));
218 } else {
219 operation_runner()->FileExists(
220 url, base::Bind(&ExpectEqHelper, test_name, expectation));
222 base::MessageLoop::current()->RunUntilIdle();
226 TEST_F(NativeMediaFileUtilTest, ReadDirectoryFiltering) {
227 PopulateDirectoryWithTestCases(root_path(),
228 kFilteringTestCases,
229 arraysize(kFilteringTestCases));
231 std::set<base::FilePath::StringType> content;
232 FileSystemURL url = CreateURL(FPL(""));
233 bool completed = false;
234 operation_runner()->ReadDirectory(
235 url, base::Bind(&DidReadDirectory, &content, &completed));
236 base::MessageLoop::current()->RunUntilIdle();
237 EXPECT_TRUE(completed);
238 EXPECT_EQ(6u, content.size());
240 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
241 base::FilePath::StringType name =
242 base::FilePath(kFilteringTestCases[i].path).BaseName().value();
243 std::set<base::FilePath::StringType>::const_iterator found =
244 content.find(name);
245 EXPECT_EQ(kFilteringTestCases[i].visible, found != content.end());
249 TEST_F(NativeMediaFileUtilTest, CreateDirectoryFiltering) {
250 // Run the loop twice. The second loop attempts to create directories that are
251 // pre-existing. Though the result should be the same.
252 for (int loop_count = 0; loop_count < 2; ++loop_count) {
253 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
254 if (kFilteringTestCases[i].is_directory) {
255 FileSystemURL root_url = CreateURL(FPL(""));
256 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
258 std::string test_name = base::StringPrintf(
259 "CreateFileAndCreateDirectoryFiltering run %d, test %" PRIuS,
260 loop_count, i);
261 base::File::Error expectation =
262 kFilteringTestCases[i].visible ?
263 base::File::FILE_OK :
264 base::File::FILE_ERROR_SECURITY;
265 operation_runner()->CreateDirectory(
266 url, false, false,
267 base::Bind(&ExpectEqHelper, test_name, expectation));
269 base::MessageLoop::current()->RunUntilIdle();
274 TEST_F(NativeMediaFileUtilTest, CopySourceFiltering) {
275 base::FilePath dest_path = root_path().AppendASCII("dest");
276 FileSystemURL dest_url = CreateURL(FPL("dest"));
278 // Run the loop twice. The first run has no source files. The second run does.
279 for (int loop_count = 0; loop_count < 2; ++loop_count) {
280 if (loop_count == 1) {
281 PopulateDirectoryWithTestCases(root_path(),
282 kFilteringTestCases,
283 arraysize(kFilteringTestCases));
285 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
286 // Always start with an empty destination directory.
287 // Copying to a non-empty destination directory is an invalid operation.
288 ASSERT_TRUE(base::DeleteFile(dest_path, true));
289 ASSERT_TRUE(base::CreateDirectory(dest_path));
291 FileSystemURL root_url = CreateURL(FPL(""));
292 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
294 std::string test_name = base::StringPrintf(
295 "CopySourceFiltering run %d test %" PRIuS, loop_count, i);
296 base::File::Error expectation = base::File::FILE_OK;
297 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
298 // If the source does not exist or is not visible.
299 expectation = base::File::FILE_ERROR_NOT_FOUND;
300 } else if (!kFilteringTestCases[i].is_directory) {
301 // Cannot copy a visible file to a directory.
302 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
304 operation_runner()->Copy(
305 url,
306 dest_url,
307 storage::FileSystemOperation::OPTION_NONE,
308 storage::FileSystemOperationRunner::CopyProgressCallback(),
309 base::Bind(&ExpectEqHelper, test_name, expectation));
310 base::MessageLoop::current()->RunUntilIdle();
315 TEST_F(NativeMediaFileUtilTest, CopyDestFiltering) {
316 // Run the loop twice. The first run has no destination files.
317 // The second run does.
318 for (int loop_count = 0; loop_count < 2; ++loop_count) {
319 if (loop_count == 1) {
320 // Reset the test directory between the two loops to remove old
321 // directories and create new ones that should pre-exist.
322 ASSERT_TRUE(base::DeleteFile(root_path(), true));
323 ASSERT_TRUE(base::CreateDirectory(root_path()));
324 PopulateDirectoryWithTestCases(root_path(),
325 kFilteringTestCases,
326 arraysize(kFilteringTestCases));
329 // Always create a dummy source data file.
330 base::FilePath src_path = root_path().AppendASCII("foo.jpg");
331 FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
332 static const char kDummyData[] = "dummy";
333 ASSERT_TRUE(base::WriteFile(src_path, kDummyData, strlen(kDummyData)));
335 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
336 if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
337 // These directories do not exist in this case, so Copy() will not
338 // treat them as directories. Thus invalidating these test cases.
339 continue;
341 FileSystemURL root_url = CreateURL(FPL(""));
342 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
344 std::string test_name = base::StringPrintf(
345 "CopyDestFiltering run %d test %" PRIuS, loop_count, i);
346 base::File::Error expectation;
347 if (loop_count == 0) {
348 // The destination path is a file here. The directory case has been
349 // handled above.
350 // If the destination path does not exist and is not visible, then
351 // creating it would be a security violation.
352 expectation =
353 kFilteringTestCases[i].visible ?
354 base::File::FILE_OK :
355 base::File::FILE_ERROR_SECURITY;
356 } else {
357 if (!kFilteringTestCases[i].visible) {
358 // If the destination path exist and is not visible, then to the copy
359 // operation, it looks like the file needs to be created, which is a
360 // security violation.
361 expectation = base::File::FILE_ERROR_SECURITY;
362 } else if (kFilteringTestCases[i].is_directory) {
363 // Cannot copy a file to a directory.
364 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
365 } else {
366 // Copying from a file to a visible file that exists is ok.
367 expectation = base::File::FILE_OK;
370 operation_runner()->Copy(
371 src_url,
372 url,
373 storage::FileSystemOperation::OPTION_NONE,
374 storage::FileSystemOperationRunner::CopyProgressCallback(),
375 base::Bind(&ExpectEqHelper, test_name, expectation));
376 base::MessageLoop::current()->RunUntilIdle();
381 TEST_F(NativeMediaFileUtilTest, MoveSourceFiltering) {
382 base::FilePath dest_path = root_path().AppendASCII("dest");
383 FileSystemURL dest_url = CreateURL(FPL("dest"));
385 // Run the loop twice. The first run has no source files. The second run does.
386 for (int loop_count = 0; loop_count < 2; ++loop_count) {
387 if (loop_count == 1) {
388 PopulateDirectoryWithTestCases(root_path(),
389 kFilteringTestCases,
390 arraysize(kFilteringTestCases));
392 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
393 // Always start with an empty destination directory.
394 // Moving to a non-empty destination directory is an invalid operation.
395 ASSERT_TRUE(base::DeleteFile(dest_path, true));
396 ASSERT_TRUE(base::CreateDirectory(dest_path));
398 FileSystemURL root_url = CreateURL(FPL(""));
399 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
401 std::string test_name = base::StringPrintf(
402 "MoveSourceFiltering run %d test %" PRIuS, loop_count, i);
403 base::File::Error expectation = base::File::FILE_OK;
404 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
405 // If the source does not exist or is not visible.
406 expectation = base::File::FILE_ERROR_NOT_FOUND;
407 } else if (!kFilteringTestCases[i].is_directory) {
408 // Cannot move a visible file to a directory.
409 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
411 operation_runner()->Move(
412 url,
413 dest_url,
414 storage::FileSystemOperation::OPTION_NONE,
415 base::Bind(&ExpectEqHelper, test_name, expectation));
416 base::MessageLoop::current()->RunUntilIdle();
421 TEST_F(NativeMediaFileUtilTest, MoveDestFiltering) {
422 // Run the loop twice. The first run has no destination files.
423 // The second run does.
424 for (int loop_count = 0; loop_count < 2; ++loop_count) {
425 if (loop_count == 1) {
426 // Reset the test directory between the two loops to remove old
427 // directories and create new ones that should pre-exist.
428 ASSERT_TRUE(base::DeleteFile(root_path(), true));
429 ASSERT_TRUE(base::CreateDirectory(root_path()));
430 PopulateDirectoryWithTestCases(root_path(),
431 kFilteringTestCases,
432 arraysize(kFilteringTestCases));
435 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
436 if (loop_count == 0 && kFilteringTestCases[i].is_directory) {
437 // These directories do not exist in this case, so Copy() will not
438 // treat them as directories. Thus invalidating these test cases.
439 continue;
442 // Create the source file for every test case because it might get moved.
443 base::FilePath src_path = root_path().AppendASCII("foo.jpg");
444 FileSystemURL src_url = CreateURL(FPL("foo.jpg"));
445 static const char kDummyData[] = "dummy";
446 ASSERT_TRUE(
447 base::WriteFile(src_path, kDummyData, strlen(kDummyData)));
449 FileSystemURL root_url = CreateURL(FPL(""));
450 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
452 std::string test_name = base::StringPrintf(
453 "MoveDestFiltering run %d test %" PRIuS, loop_count, i);
454 base::File::Error expectation;
455 if (loop_count == 0) {
456 // The destination path is a file here. The directory case has been
457 // handled above.
458 // If the destination path does not exist and is not visible, then
459 // creating it would be a security violation.
460 expectation =
461 kFilteringTestCases[i].visible ?
462 base::File::FILE_OK :
463 base::File::FILE_ERROR_SECURITY;
464 } else {
465 if (!kFilteringTestCases[i].visible) {
466 // If the destination path exist and is not visible, then to the move
467 // operation, it looks like the file needs to be created, which is a
468 // security violation.
469 expectation = base::File::FILE_ERROR_SECURITY;
470 } else if (kFilteringTestCases[i].is_directory) {
471 // Cannot move a file to a directory.
472 expectation = base::File::FILE_ERROR_INVALID_OPERATION;
473 } else {
474 // Moving from a file to a visible file that exists is ok.
475 expectation = base::File::FILE_OK;
478 operation_runner()->Move(
479 src_url,
480 url,
481 storage::FileSystemOperation::OPTION_NONE,
482 base::Bind(&ExpectEqHelper, test_name, expectation));
483 base::MessageLoop::current()->RunUntilIdle();
488 TEST_F(NativeMediaFileUtilTest, GetMetadataFiltering) {
489 // Run the loop twice. The first run has no files. The second run does.
490 for (int loop_count = 0; loop_count < 2; ++loop_count) {
491 if (loop_count == 1) {
492 PopulateDirectoryWithTestCases(root_path(),
493 kFilteringTestCases,
494 arraysize(kFilteringTestCases));
496 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
497 FileSystemURL root_url = CreateURL(FPL(""));
498 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
500 std::string test_name = base::StringPrintf(
501 "GetMetadataFiltering run %d test %" PRIuS, loop_count, i);
502 base::File::Error expectation = base::File::FILE_OK;
503 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
504 // Cannot get metadata from files that do not exist or are not visible.
505 expectation = base::File::FILE_ERROR_NOT_FOUND;
507 operation_runner()->GetMetadata(
508 url,
509 base::Bind(&ExpectMetadataEqHelper,
510 test_name,
511 expectation,
512 kFilteringTestCases[i].is_directory));
513 base::MessageLoop::current()->RunUntilIdle();
518 TEST_F(NativeMediaFileUtilTest, RemoveFileFiltering) {
519 // Run the loop twice. The first run has no files. The second run does.
520 for (int loop_count = 0; loop_count < 2; ++loop_count) {
521 if (loop_count == 1) {
522 PopulateDirectoryWithTestCases(root_path(),
523 kFilteringTestCases,
524 arraysize(kFilteringTestCases));
526 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
527 FileSystemURL root_url = CreateURL(FPL(""));
528 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
530 std::string test_name = base::StringPrintf(
531 "RemoveFiltering run %d test %" PRIuS, loop_count, i);
532 base::File::Error expectation = base::File::FILE_OK;
533 if (loop_count == 0 || !kFilteringTestCases[i].visible) {
534 // Cannot remove files that do not exist or are not visible.
535 expectation = base::File::FILE_ERROR_NOT_FOUND;
536 } else if (kFilteringTestCases[i].is_directory) {
537 expectation = base::File::FILE_ERROR_NOT_A_FILE;
539 operation_runner()->RemoveFile(
540 url, base::Bind(&ExpectEqHelper, test_name, expectation));
541 base::MessageLoop::current()->RunUntilIdle();
546 void CreateSnapshotCallback(
547 base::File::Error* error,
548 base::File::Error result,
549 const base::File::Info&,
550 const base::FilePath&,
551 const scoped_refptr<storage::ShareableFileReference>&) {
552 *error = result;
555 TEST_F(NativeMediaFileUtilTest, CreateSnapshot) {
556 PopulateDirectoryWithTestCases(root_path(),
557 kFilteringTestCases,
558 arraysize(kFilteringTestCases));
559 for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
560 if (kFilteringTestCases[i].is_directory ||
561 !kFilteringTestCases[i].visible) {
562 continue;
564 FileSystemURL root_url = CreateURL(FPL(""));
565 FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
566 base::File::Error expected_error, error;
567 if (kFilteringTestCases[i].media_file)
568 expected_error = base::File::FILE_OK;
569 else
570 expected_error = base::File::FILE_ERROR_SECURITY;
571 error = base::File::FILE_ERROR_FAILED;
572 operation_runner()->CreateSnapshotFile(url,
573 base::Bind(CreateSnapshotCallback, &error));
574 base::MessageLoop::current()->RunUntilIdle();
575 ASSERT_EQ(expected_error, error);