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/files/file_path.h" 8 #include "base/files/file_util.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 "storage/browser/fileapi/copy_or_move_file_validator.h" 20 #include "storage/browser/fileapi/file_system_backend.h" 21 #include "storage/browser/fileapi/file_system_context.h" 22 #include "storage/browser/fileapi/file_system_operation_runner.h" 23 #include "storage/browser/fileapi/file_system_url.h" 24 #include "storage/browser/fileapi/isolated_context.h" 25 #include "storage/common/fileapi/file_system_types.h" 26 #include "testing/gtest/include/gtest/gtest.h" 27 28 namespace { 29 30 const char kOrigin[] = "http://foo"; 31 32 const 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 36 const char kInvalidMediaFile[] = "Not a media file"; 37 38 const int64 kNoFileSize = -1; 39 40 void HandleCheckFileResult(int64 expected_size, 41 const base::Callback<void(bool success)>& callback, 42 base::File::Error result, 43 const base::File::Info& file_info) { 44 if (result == base::File::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 59 base::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 68 class 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(base::CreateDirectory(src_path)); 109 110 ScopedVector<storage::FileSystemBackend> additional_providers; 111 additional_providers.push_back(new content::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 content::CreateFileSystemContextWithAdditionalProvidersForTesting( 117 NULL, additional_providers.Pass(), base); 118 119 move_src_ = file_system_context_->CreateCrackedFileSystemURL( 120 GURL(kOrigin), 121 storage::kFileSystemTypeTest, 122 base::FilePath::FromUTF8Unsafe(filename)); 123 124 test_file_size_ = content.size(); 125 base::FilePath test_file = src_path.AppendASCII(filename); 126 ASSERT_EQ(test_file_size_, 127 base::WriteFile(test_file, content.data(), test_file_size_)); 128 129 base::FilePath dest_path = base.AppendASCII("dest_fs"); 130 ASSERT_TRUE(base::CreateDirectory(dest_path)); 131 std::string dest_fsid = 132 storage::IsolatedContext::GetInstance()->RegisterFileSystemForPath( 133 storage::kFileSystemTypeNativeMedia, 134 std::string(), 135 dest_path, 136 NULL); 137 138 size_t extension_index = filename.find_last_of("."); 139 ASSERT_NE(std::string::npos, extension_index); 140 std::string extension = filename.substr(extension_index); 141 std::string dest_root_fs_url = storage::GetIsolatedFileSystemRootURIString( 142 GURL(kOrigin), dest_fsid, "dest_fs/"); 143 move_dest_ = file_system_context_->CrackURL(GURL( 144 dest_root_fs_url + "move_dest" + extension)); 145 146 content::BrowserThread::PostTask( 147 content::BrowserThread::IO, 148 FROM_HERE, 149 base::Bind(&MediaFileValidatorTest::CheckFiles, 150 base::Unretained(this), true, 151 base::Bind(&MediaFileValidatorTest::OnTestFilesReady, 152 base::Unretained(this), expected_result))); 153 } 154 155 void SetupFromFileOnFileThread(const std::string& filename, 156 const base::FilePath& source, 157 bool expected_result) { 158 std::string content; 159 ASSERT_TRUE(base::ReadFileToString(source, &content)); 160 SetupOnFileThread(filename, content, expected_result); 161 } 162 163 // Check that exactly one of |move_src_| and |move_dest_| exists. 164 // |src_expected| indicates which one should exist. When complete, 165 // |callback| is called with success/failure. 166 void CheckFiles(bool src_expected, 167 const base::Callback<void(bool success)>& callback) { 168 CheckFile(move_src_, src_expected ? test_file_size_ : kNoFileSize, 169 base::Bind(&MediaFileValidatorTest::OnCheckFilesFirstResult, 170 base::Unretained(this), !src_expected, callback)); 171 } 172 173 // Helper that checks a file has the |expected_size|, which may be 174 // |kNoFileSize| if the file should not exist. |callback| is called 175 // with success/failure. 176 void CheckFile(storage::FileSystemURL url, 177 int64 expected_size, 178 const base::Callback<void(bool success)>& callback) { 179 operation_runner()->GetMetadata(url, 180 base::Bind(&HandleCheckFileResult, 181 expected_size, callback)); 182 } 183 184 // Helper that checks the result of |move_src_| lookup and then checks 185 // |move_dest_| if all is as expected. 186 void OnCheckFilesFirstResult(bool dest_expected, 187 const base::Callback<void(bool)>& callback, 188 bool src_result) { 189 EXPECT_TRUE(src_result); 190 if (!src_result) { 191 callback.Run(false); 192 return; 193 } 194 CheckFile(move_dest_, dest_expected ? test_file_size_ : kNoFileSize, 195 callback); 196 } 197 198 // Assert |test_files_ready| and then do the actual test of moving 199 // |move_src_| to |move_dest_|. 200 void OnTestFilesReady(bool expected_result, bool test_files_ready) { 201 ASSERT_TRUE(test_files_ready); 202 operation_runner()->Move(move_src_, 203 move_dest_, 204 storage::FileSystemOperation::OPTION_NONE, 205 base::Bind(&MediaFileValidatorTest::OnMoveResult, 206 base::Unretained(this), 207 expected_result)); 208 } 209 210 // Check that the move succeeded/failed based on expectation and then 211 // check that the right file exists. 212 void OnMoveResult(bool expected_result, base::File::Error result) { 213 if (expected_result) 214 EXPECT_EQ(base::File::FILE_OK, result); 215 else 216 EXPECT_EQ(base::File::FILE_ERROR_SECURITY, result); 217 CheckFiles(!expected_result, 218 base::Bind(&MediaFileValidatorTest::OnTestFilesCheckResult, 219 base::Unretained(this))); 220 } 221 222 // Check that the correct test file exists and then post the result back 223 // to the UI thread. 224 void OnTestFilesCheckResult(bool result) { 225 EXPECT_TRUE(result); 226 content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, 227 loop_runner_->QuitClosure()); 228 } 229 230 storage::FileSystemOperationRunner* operation_runner() { 231 return file_system_context_->operation_runner(); 232 } 233 234 base::ScopedTempDir base_dir_; 235 236 scoped_refptr<storage::FileSystemContext> file_system_context_; 237 238 int test_file_size_; 239 240 storage::FileSystemURL move_src_; 241 storage::FileSystemURL move_dest_; 242 243 scoped_refptr<content::MessageLoopRunner> loop_runner_; 244 245 DISALLOW_COPY_AND_ASSIGN(MediaFileValidatorTest); 246 }; 247 248 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, UnsupportedExtension) { 249 MoveTest("a.txt", std::string(kValidImage, arraysize(kValidImage)), false); 250 } 251 252 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, ValidImage) { 253 MoveTest("a.webp", std::string(kValidImage, arraysize(kValidImage)), true); 254 } 255 256 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, InvalidImage) { 257 MoveTest("a.webp", std::string(kInvalidMediaFile, 258 arraysize(kInvalidMediaFile)), false); 259 } 260 261 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, InvalidAudio) { 262 MoveTest("a.ogg", std::string(kInvalidMediaFile, 263 arraysize(kInvalidMediaFile)), false); 264 } 265 266 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, ValidAudio) { 267 base::FilePath test_file = GetMediaTestDir(); 268 ASSERT_FALSE(test_file.empty()); 269 test_file = test_file.AppendASCII("sfx.ogg"); 270 MoveTestFromFile("sfx.ogg", test_file, true); 271 } 272 273 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, InvalidVideo) { 274 base::FilePath test_file = GetMediaTestDir(); 275 ASSERT_FALSE(test_file.empty()); 276 test_file = test_file.AppendASCII("no_streams.webm"); 277 MoveTestFromFile("no_streams.webm", test_file, false); 278 } 279 280 IN_PROC_BROWSER_TEST_F(MediaFileValidatorTest, ValidVideo) { 281 base::FilePath test_file = GetMediaTestDir(); 282 ASSERT_FALSE(test_file.empty()); 283 test_file = test_file.AppendASCII("bear-320x240-multitrack.webm"); 284 MoveTestFromFile("multitrack.webm", test_file, true); 285 } 286