Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / fileapi / native_media_file_util_unittest.cc
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 #include <set>
6 #include <string>
7
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"
29
30 #define FPL(x) FILE_PATH_LITERAL(x)
31
32 using storage::FileSystemOperation;
33 using storage::FileSystemURL;
34
35 namespace {
36
37 typedef FileSystemOperation::FileEntryList FileEntryList;
38
39 struct FilteringTestCase {
40   const base::FilePath::CharType* path;
41   bool is_directory;
42   bool visible;
43   bool media_file;
44   const char* content;
45 };
46
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 },
53
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" },
65 };
66
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;
71 }
72
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;
81 }
82
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);
93 }
94
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));
106     }
107   }
108 }
109
110 }  // namespace
111
112 class NativeMediaFileUtilTest : public testing::Test {
113  public:
114   NativeMediaFileUtilTest()
115       : io_thread_(content::BrowserThread::IO, &message_loop_) {
116   }
117
118   virtual void SetUp() {
119     ASSERT_TRUE(data_dir_.CreateUniqueTempDir());
120     ASSERT_TRUE(base::CreateDirectory(root_path()));
121
122     scoped_refptr<storage::SpecialStoragePolicy> storage_policy =
123         new content::MockSpecialStoragePolicy();
124
125     ScopedVector<storage::FileSystemBackend> additional_providers;
126     additional_providers.push_back(new MediaFileSystemBackend(
127         data_dir_.path(), base::MessageLoopProxy::current().get()));
128
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());
139
140     filesystem_id_ = isolated_context()->RegisterFileSystemForPath(
141         storage::kFileSystemTypeNativeMedia, std::string(), root_path(), NULL);
142
143     isolated_context()->AddReference(filesystem_id_);
144   }
145
146   virtual void TearDown() {
147     isolated_context()->RemoveReference(filesystem_id_);
148     file_system_context_ = NULL;
149   }
150
151  protected:
152   storage::FileSystemContext* file_system_context() {
153     return file_system_context_.get();
154   }
155
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));
161   }
162
163   storage::IsolatedContext* isolated_context() {
164     return storage::IsolatedContext::GetInstance();
165   }
166
167   base::FilePath root_path() {
168     return data_dir_.path().Append(FPL("Media Directory"));
169   }
170
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));
176   }
177
178   GURL origin() {
179     return GURL("http://example.com");
180   }
181
182   storage::FileSystemType type() { return storage::kFileSystemTypeNativeMedia; }
183
184   storage::FileSystemOperationRunner* operation_runner() {
185     return file_system_context_->operation_runner();
186   }
187
188  private:
189   base::MessageLoop message_loop_;
190   content::TestBrowserThread io_thread_;
191
192   base::ScopedTempDir data_dir_;
193   scoped_refptr<storage::FileSystemContext> file_system_context_;
194
195   std::string filesystem_id_;
196
197   DISALLOW_COPY_AND_ASSIGN(NativeMediaFileUtilTest);
198 };
199
200 TEST_F(NativeMediaFileUtilTest, DirectoryExistsAndFileExistsFiltering) {
201   PopulateDirectoryWithTestCases(root_path(),
202                                  kFilteringTestCases,
203                                  arraysize(kFilteringTestCases));
204
205   for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
206     FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
207
208     base::File::Error expectation =
209         kFilteringTestCases[i].visible ?
210         base::File::FILE_OK :
211         base::File::FILE_ERROR_NOT_FOUND;
212
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));
221     }
222     base::MessageLoop::current()->RunUntilIdle();
223   }
224 }
225
226 TEST_F(NativeMediaFileUtilTest, ReadDirectoryFiltering) {
227   PopulateDirectoryWithTestCases(root_path(),
228                                  kFilteringTestCases,
229                                  arraysize(kFilteringTestCases));
230
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());
239
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());
246   }
247 }
248
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);
257
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));
268       }
269       base::MessageLoop::current()->RunUntilIdle();
270     }
271   }
272 }
273
274 TEST_F(NativeMediaFileUtilTest, CopySourceFiltering) {
275   base::FilePath dest_path = root_path().AppendASCII("dest");
276   FileSystemURL dest_url = CreateURL(FPL("dest"));
277
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));
284     }
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));
290
291       FileSystemURL root_url = CreateURL(FPL(""));
292       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
293
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;
303       }
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();
311     }
312   }
313 }
314
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));
327     }
328
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)));
334
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;
340       }
341       FileSystemURL root_url = CreateURL(FPL(""));
342       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
343
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;
368         }
369       }
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();
377     }
378   }
379 }
380
381 TEST_F(NativeMediaFileUtilTest, MoveSourceFiltering) {
382   base::FilePath dest_path = root_path().AppendASCII("dest");
383   FileSystemURL dest_url = CreateURL(FPL("dest"));
384
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));
391     }
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));
397
398       FileSystemURL root_url = CreateURL(FPL(""));
399       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
400
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;
410       }
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();
417     }
418   }
419 }
420
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));
433     }
434
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;
440       }
441
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)));
448
449       FileSystemURL root_url = CreateURL(FPL(""));
450       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
451
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;
476         }
477       }
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();
484     }
485   }
486 }
487
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));
495     }
496     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
497       FileSystemURL root_url = CreateURL(FPL(""));
498       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
499
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;
506       }
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();
514     }
515   }
516 }
517
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));
525     }
526     for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
527       FileSystemURL root_url = CreateURL(FPL(""));
528       FileSystemURL url = CreateURL(kFilteringTestCases[i].path);
529
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;
538       }
539       operation_runner()->RemoveFile(
540           url, base::Bind(&ExpectEqHelper, test_name, expectation));
541       base::MessageLoop::current()->RunUntilIdle();
542     }
543   }
544 }
545
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;
553 }
554
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;
563     }
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);
576   }
577 }