media_file_validator_browsertest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
1// Copyright 2013 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 "base/basictypes.h"
6#include "base/bind.h"
7#include "base/file_util.h"
8#include "base/files/file_path.h"
9#include "base/files/scoped_temp_dir.h"
10#include "base/message_loop/message_loop.h"
11#include "base/message_loop/message_loop_proxy.h"
12#include "base/path_service.h"
13#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
14#include "chrome/test/base/in_process_browser_test.h"
15#include "content/public/test/browser_test.h"
16#include "content/public/test/test_file_system_backend.h"
17#include "content/public/test/test_file_system_context.h"
18#include "content/public/test/test_utils.h"
19#include "testing/gtest/include/gtest/gtest.h"
20#include "webkit/browser/fileapi/copy_or_move_file_validator.h"
21#include "webkit/browser/fileapi/file_system_backend.h"
22#include "webkit/browser/fileapi/file_system_context.h"
23#include "webkit/browser/fileapi/file_system_operation_runner.h"
24#include "webkit/browser/fileapi/file_system_url.h"
25#include "webkit/browser/fileapi/isolated_context.h"
26#include "webkit/common/fileapi/file_system_types.h"
27
28namespace {
29
30const char kOrigin[] = "http://foo";
31
32const char kValidImage[] = "RIFF0\0\0\0WEBPVP8 $\0\0\0\xB2\x02\0\x9D\x01\x2A"
33                           "\x01\0\x01\0\x2F\x9D\xCE\xE7s\xA8((((\x01\x9CK(\0"
34                           "\x05\xCE\xB3l\0\0\xFE\xD8\x80\0\0";
35
36const char kInvalidMediaFile[] = "Not a media file";
37
38const int64 kNoFileSize = -1;
39
40void HandleCheckFileResult(int64 expected_size,
41                           const base::Callback<void(bool success)>& callback,
42                           base::PlatformFileError result,
43                           const base::PlatformFileInfo& file_info) {
44  if (result == base::PLATFORM_FILE_OK) {
45    if (!file_info.is_directory && expected_size != kNoFileSize &&
46        file_info.size == expected_size) {
47      callback.Run(true);
48      return;
49    }
50  } else {
51    if (expected_size == kNoFileSize) {
52      callback.Run(true);
53      return;
54    }
55  }
56  callback.Run(false);
57}
58
59base::FilePath GetMediaTestDir() {
60  base::FilePath test_file;
61  if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_file))
62    return base::FilePath();
63  return test_file.AppendASCII("media").AppendASCII("test").AppendASCII("data");
64}
65
66}  // namespace
67
68class MediaFileValidatorTest : public InProcessBrowserTest {
69 public:
70  MediaFileValidatorTest() : test_file_size_(0) {}
71
72  virtual ~MediaFileValidatorTest() {}
73
74  // Write |content| into |filename| in a test file system and try to move
75  // it into a media file system.  The result is compared to |expected_result|.
76  void MoveTest(const std::string& filename, const std::string& content,
77                bool expected_result) {
78    content::BrowserThread::PostTask(
79        content::BrowserThread::FILE,
80        FROM_HERE,
81        base::Bind(&MediaFileValidatorTest::SetupOnFileThread,
82                   base::Unretained(this), filename, content, expected_result));
83    loop_runner_ = new content::MessageLoopRunner;
84    loop_runner_->Run();
85  }
86
87  // Write |source| into |filename| in a test file system and try to move it
88  // into a media file system.  The result is compared to |expected_result|.
89  void MoveTestFromFile(const std::string& filename,
90                        const base::FilePath& source, bool expected_result) {
91    content::BrowserThread::PostTask(
92        content::BrowserThread::FILE,
93        FROM_HERE,
94        base::Bind(&MediaFileValidatorTest::SetupFromFileOnFileThread,
95                   base::Unretained(this), filename, source, expected_result));
96    loop_runner_ = new content::MessageLoopRunner;
97    loop_runner_->Run();
98  }
99
100 private:
101  // Create the test files, filesystem objects, etc.
102  void SetupOnFileThread(const std::string& filename,
103                         const std::string& content,
104                         bool expected_result) {
105    ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
106    base::FilePath base = base_dir_.path();
107    base::FilePath src_path = base.AppendASCII("src_fs");
108    ASSERT_TRUE(file_util::CreateDirectory(src_path));
109
110    ScopedVector<fileapi::FileSystemBackend> additional_providers;
111    additional_providers.push_back(new fileapi::TestFileSystemBackend(
112        base::MessageLoopProxy::current().get(), src_path));
113    additional_providers.push_back(new MediaFileSystemBackend(
114        base, base::MessageLoopProxy::current().get()));
115    file_system_context_ =
116        fileapi::CreateFileSystemContextWithAdditionalProvidersForTesting(
117            NULL, additional_providers.Pass(), base);
118
119    move_src_ = file_system_context_->CreateCrackedFileSystemURL(
120        GURL(kOrigin), fileapi::kFileSystemTypeTest,
121        base::FilePath::FromUTF8Unsafe(filename));
122
123    test_file_size_ = content.size();
124    base::FilePath test_file = src_path.AppendASCII(filename);
125    ASSERT_EQ(test_file_size_,
126              file_util::WriteFile(test_file, content.data(), test_file_size_));
127
128    base::FilePath dest_path = base.AppendASCII("dest_fs");
129    ASSERT_TRUE(file_util::CreateDirectory(dest_path));
130    std::string dest_fsid =
131        fileapi::IsolatedContext::GetInstance()->RegisterFileSystemForPath(
132            fileapi::kFileSystemTypeNativeMedia, dest_path, NULL);
133
134    size_t extension_index = filename.find_last_of(".");
135    ASSERT_NE(std::string::npos, extension_index);
136    std::string extension = filename.substr(extension_index);
137    std::string dest_root_fs_url = fileapi::GetIsolatedFileSystemRootURIString(
138        GURL(kOrigin), dest_fsid, "dest_fs/");
139    move_dest_ = file_system_context_->CrackURL(GURL(
140          dest_root_fs_url + "move_dest" + extension));
141
142    content::BrowserThread::PostTask(
143        content::BrowserThread::IO,
144        FROM_HERE,
145        base::Bind(&MediaFileValidatorTest::CheckFiles,
146                   base::Unretained(this), true,
147                   base::Bind(&MediaFileValidatorTest::OnTestFilesReady,
148                              base::Unretained(this), expected_result)));
149  }
150
151  void SetupFromFileOnFileThread(const std::string& filename,
152                                 const base::FilePath& source,
153                                 bool expected_result) {
154    std::string content;
155    ASSERT_TRUE(base::ReadFileToString(source, &content));
156    SetupOnFileThread(filename, content, expected_result);
157  }
158
159  // Check that exactly one of |move_src_| and |move_dest_| exists.
160  // |src_expected| indicates which one should exist.  When complete,
161  // |callback| is called with success/failure.
162  void CheckFiles(bool src_expected,
163                  const base::Callback<void(bool success)>& callback) {
164    CheckFile(move_src_, src_expected ? test_file_size_ : kNoFileSize,
165              base::Bind(&MediaFileValidatorTest::OnCheckFilesFirstResult,
166                         base::Unretained(this), !src_expected, callback));
167  }
168
169  // Helper that checks a file has the |expected_size|, which may be
170  // |kNoFileSize| if the file should not exist.  |callback| is called
171  // with success/failure.
172  void CheckFile(fileapi::FileSystemURL url,
173                 int64 expected_size,
174                 const base::Callback<void(bool success)>& callback) {
175    operation_runner()->GetMetadata(url,
176                                    base::Bind(&HandleCheckFileResult,
177                                               expected_size, callback));
178  }
179
180  // Helper that checks the result of |move_src_| lookup and then checks
181  // |move_dest_| if all is as expected.
182  void OnCheckFilesFirstResult(bool dest_expected,
183                               const base::Callback<void(bool)>& callback,
184                               bool src_result) {
185    EXPECT_TRUE(src_result);
186    if (!src_result) {
187      callback.Run(false);
188      return;
189    }
190    CheckFile(move_dest_, dest_expected ? test_file_size_ : kNoFileSize,
191              callback);
192  }
193
194  // Assert |test_files_ready| and then do the actual test of moving
195  // |move_src_| to |move_dest_|.
196  void OnTestFilesReady(bool expected_result, bool test_files_ready) {
197    ASSERT_TRUE(test_files_ready);
198    operation_runner()->Move(
199        move_src_, move_dest_, fileapi::FileSystemOperation::OPTION_NONE,
200        base::Bind(&MediaFileValidatorTest::OnMoveResult,
201                   base::Unretained(this), expected_result));
202  }
203
204  // Check that the move succeeded/failed based on expectation and then
205  // check that the right file exists.
206  void OnMoveResult(bool expected_result, base::PlatformFileError result) {
207    if (expected_result)
208      EXPECT_EQ(base::PLATFORM_FILE_OK, result);
209    else
210      EXPECT_EQ(base::PLATFORM_FILE_ERROR_SECURITY, result);
211    CheckFiles(!expected_result,
212               base::Bind(&MediaFileValidatorTest::OnTestFilesCheckResult,
213                          base::Unretained(this)));
214  }
215
216  // Check that the correct test file exists and then post the result back
217  // to the UI thread.
218  void OnTestFilesCheckResult(bool result) {
219    EXPECT_TRUE(result);
220    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
221                                     loop_runner_->QuitClosure());
222  }
223
224  fileapi::FileSystemOperationRunner* operation_runner() {
225    return file_system_context_->operation_runner();
226  }
227
228  base::ScopedTempDir base_dir_;
229
230  scoped_refptr<fileapi::FileSystemContext> file_system_context_;
231
232  int test_file_size_;
233
234  fileapi::FileSystemURL move_src_;
235  fileapi::FileSystemURL move_dest_;
236
237  scoped_refptr<content::MessageLoopRunner> loop_runner_;
238
239  DISALLOW_COPY_AND_ASSIGN(MediaFileValidatorTest);
240};
241
242IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, UnsupportedExtension) {
243  MoveTest("a.txt", std::string(kValidImage, arraysize(kValidImage)), false);
244}
245
246IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, ValidImage) {
247  MoveTest("a.webp", std::string(kValidImage, arraysize(kValidImage)), true);
248}
249
250IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, InvalidImage) {
251  MoveTest("a.webp", std::string(kInvalidMediaFile,
252           arraysize(kInvalidMediaFile)), false);
253}
254
255IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, InvalidAudio) {
256  MoveTest("a.ogg", std::string(kInvalidMediaFile,
257           arraysize(kInvalidMediaFile)), false);
258}
259
260IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, ValidAudio) {
261  base::FilePath test_file = GetMediaTestDir();
262  ASSERT_FALSE(test_file.empty());
263  test_file = test_file.AppendASCII("sfx.ogg");
264  MoveTestFromFile("sfx.ogg", test_file, true);
265}
266
267IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, InvalidVideo) {
268  base::FilePath test_file = GetMediaTestDir();
269  ASSERT_FALSE(test_file.empty());
270  test_file = test_file.AppendASCII("no_streams.webm");
271  MoveTestFromFile("no_streams.webm", test_file, false);
272}
273
274IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, ValidVideo) {
275  base::FilePath test_file = GetMediaTestDir();
276  ASSERT_FALSE(test_file.empty());
277  test_file = test_file.AppendASCII("bear-320x240-multitrack.webm");
278  MoveTestFromFile("multitrack.webm", test_file, true);
279}
280