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/scoped_temp_dir.h" 9 #include "base/message_loop/message_loop.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 #include "webkit/browser/fileapi/async_file_test_helper.h" 12 #include "webkit/browser/fileapi/copy_or_move_file_validator.h" 13 #include "webkit/browser/fileapi/external_mount_points.h" 14 #include "webkit/browser/fileapi/file_system_backend.h" 15 #include "webkit/browser/fileapi/file_system_context.h" 16 #include "webkit/browser/fileapi/file_system_url.h" 17 #include "webkit/browser/fileapi/isolated_context.h" 18 #include "webkit/browser/fileapi/mock_file_system_context.h" 19 #include "webkit/browser/fileapi/test_file_system_backend.h" 20 #include "webkit/browser/quota/mock_special_storage_policy.h" 21 #include "webkit/common/blob/shareable_file_reference.h" 22 #include "webkit/common/fileapi/file_system_util.h" 23 24 namespace fileapi { 25 26 namespace { 27 28 const FileSystemType kNoValidatorType = kFileSystemTypeTemporary; 29 const FileSystemType kWithValidatorType = kFileSystemTypeTest; 30 31 void ExpectOk(const GURL& origin_url, 32 const std::string& name, 33 base::PlatformFileError error) { 34 ASSERT_EQ(base::PLATFORM_FILE_OK, error); 35 } 36 37 class CopyOrMoveFileValidatorTestHelper { 38 public: 39 CopyOrMoveFileValidatorTestHelper( 40 const GURL& origin, 41 FileSystemType src_type, 42 FileSystemType dest_type) 43 : origin_(origin), 44 src_type_(src_type), 45 dest_type_(dest_type) {} 46 47 ~CopyOrMoveFileValidatorTestHelper() { 48 file_system_context_ = NULL; 49 base::MessageLoop::current()->RunUntilIdle(); 50 } 51 52 void SetUp() { 53 ASSERT_TRUE(base_.CreateUniqueTempDir()); 54 base::FilePath base_dir = base_.path(); 55 56 file_system_context_ = CreateFileSystemContextForTesting(NULL, base_dir); 57 58 // Set up TestFileSystemBackend to require CopyOrMoveFileValidator. 59 FileSystemBackend* test_file_system_backend = 60 file_system_context_->GetFileSystemBackend(kWithValidatorType); 61 static_cast<TestFileSystemBackend*>(test_file_system_backend)-> 62 set_require_copy_or_move_validator(true); 63 64 // Sets up source. 65 FileSystemBackend* src_file_system_backend = 66 file_system_context_->GetFileSystemBackend(src_type_); 67 src_file_system_backend->OpenFileSystem( 68 origin_, src_type_, 69 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, 70 base::Bind(&ExpectOk)); 71 base::MessageLoop::current()->RunUntilIdle(); 72 ASSERT_EQ(base::PLATFORM_FILE_OK, CreateDirectory(SourceURL(""))); 73 74 // Sets up dest. 75 DCHECK_EQ(kWithValidatorType, dest_type_); 76 ASSERT_EQ(base::PLATFORM_FILE_OK, CreateDirectory(DestURL(""))); 77 78 copy_src_ = SourceURL("copy_src.jpg"); 79 move_src_ = SourceURL("move_src.jpg"); 80 copy_dest_ = DestURL("copy_dest.jpg"); 81 move_dest_ = DestURL("move_dest.jpg"); 82 83 ASSERT_EQ(base::PLATFORM_FILE_OK, CreateFile(copy_src_, 10)); 84 ASSERT_EQ(base::PLATFORM_FILE_OK, CreateFile(move_src_, 10)); 85 86 ASSERT_TRUE(FileExists(copy_src_, 10)); 87 ASSERT_TRUE(FileExists(move_src_, 10)); 88 ASSERT_FALSE(FileExists(copy_dest_, 10)); 89 ASSERT_FALSE(FileExists(move_dest_, 10)); 90 } 91 92 void SetMediaCopyOrMoveFileValidatorFactory( 93 scoped_ptr<CopyOrMoveFileValidatorFactory> factory) { 94 TestFileSystemBackend* backend = static_cast<TestFileSystemBackend*>( 95 file_system_context_->GetFileSystemBackend(kWithValidatorType)); 96 backend->InitializeCopyOrMoveFileValidatorFactory(factory.Pass()); 97 } 98 99 void CopyTest(base::PlatformFileError expected) { 100 ASSERT_TRUE(FileExists(copy_src_, 10)); 101 ASSERT_FALSE(FileExists(copy_dest_, 10)); 102 103 EXPECT_EQ(expected, 104 AsyncFileTestHelper::Copy( 105 file_system_context_.get(), copy_src_, copy_dest_)); 106 107 EXPECT_TRUE(FileExists(copy_src_, 10)); 108 if (expected == base::PLATFORM_FILE_OK) 109 EXPECT_TRUE(FileExists(copy_dest_, 10)); 110 else 111 EXPECT_FALSE(FileExists(copy_dest_, 10)); 112 }; 113 114 void MoveTest(base::PlatformFileError expected) { 115 ASSERT_TRUE(FileExists(move_src_, 10)); 116 ASSERT_FALSE(FileExists(move_dest_, 10)); 117 118 EXPECT_EQ(expected, 119 AsyncFileTestHelper::Move( 120 file_system_context_.get(), move_src_, move_dest_)); 121 122 if (expected == base::PLATFORM_FILE_OK) { 123 EXPECT_FALSE(FileExists(move_src_, 10)); 124 EXPECT_TRUE(FileExists(move_dest_, 10)); 125 } else { 126 EXPECT_TRUE(FileExists(move_src_, 10)); 127 EXPECT_FALSE(FileExists(move_dest_, 10)); 128 } 129 }; 130 131 private: 132 FileSystemURL SourceURL(const std::string& path) { 133 return file_system_context_->CreateCrackedFileSystemURL( 134 origin_, src_type_, 135 base::FilePath().AppendASCII("src").AppendASCII(path)); 136 } 137 138 FileSystemURL DestURL(const std::string& path) { 139 return file_system_context_->CreateCrackedFileSystemURL( 140 origin_, dest_type_, 141 base::FilePath().AppendASCII("dest").AppendASCII(path)); 142 } 143 144 base::PlatformFileError CreateFile(const FileSystemURL& url, size_t size) { 145 base::PlatformFileError result = 146 AsyncFileTestHelper::CreateFile(file_system_context_.get(), url); 147 if (result != base::PLATFORM_FILE_OK) 148 return result; 149 return AsyncFileTestHelper::TruncateFile( 150 file_system_context_.get(), url, size); 151 } 152 153 base::PlatformFileError CreateDirectory(const FileSystemURL& url) { 154 return AsyncFileTestHelper::CreateDirectory(file_system_context_.get(), 155 url); 156 } 157 158 bool FileExists(const FileSystemURL& url, int64 expected_size) { 159 return AsyncFileTestHelper::FileExists( 160 file_system_context_.get(), url, expected_size); 161 } 162 163 base::ScopedTempDir base_; 164 165 const GURL origin_; 166 167 const FileSystemType src_type_; 168 const FileSystemType dest_type_; 169 std::string src_fsid_; 170 std::string dest_fsid_; 171 172 base::MessageLoop message_loop_; 173 scoped_refptr<FileSystemContext> file_system_context_; 174 175 FileSystemURL copy_src_; 176 FileSystemURL copy_dest_; 177 FileSystemURL move_src_; 178 FileSystemURL move_dest_; 179 180 DISALLOW_COPY_AND_ASSIGN(CopyOrMoveFileValidatorTestHelper); 181 }; 182 183 // For TestCopyOrMoveFileValidatorFactory 184 enum Validity { 185 VALID, 186 PRE_WRITE_INVALID, 187 POST_WRITE_INVALID 188 }; 189 190 class TestCopyOrMoveFileValidatorFactory 191 : public CopyOrMoveFileValidatorFactory { 192 public: 193 // A factory that creates validators that accept everything or nothing. 194 // TODO(gbillock): switch args to enum or something 195 explicit TestCopyOrMoveFileValidatorFactory(Validity validity) 196 : validity_(validity) {} 197 virtual ~TestCopyOrMoveFileValidatorFactory() {} 198 199 virtual CopyOrMoveFileValidator* CreateCopyOrMoveFileValidator( 200 const FileSystemURL& /*src_url*/, 201 const base::FilePath& /*platform_path*/) OVERRIDE { 202 return new TestCopyOrMoveFileValidator(validity_); 203 } 204 205 private: 206 class TestCopyOrMoveFileValidator : public CopyOrMoveFileValidator { 207 public: 208 explicit TestCopyOrMoveFileValidator(Validity validity) 209 : result_(validity == VALID || validity == POST_WRITE_INVALID 210 ? base::PLATFORM_FILE_OK 211 : base::PLATFORM_FILE_ERROR_SECURITY), 212 write_result_(validity == VALID || validity == PRE_WRITE_INVALID 213 ? base::PLATFORM_FILE_OK 214 : base::PLATFORM_FILE_ERROR_SECURITY) { 215 } 216 virtual ~TestCopyOrMoveFileValidator() {} 217 218 virtual void StartPreWriteValidation( 219 const ResultCallback& result_callback) OVERRIDE { 220 // Post the result since a real validator must do work asynchronously. 221 base::MessageLoop::current()->PostTask( 222 FROM_HERE, base::Bind(result_callback, result_)); 223 } 224 225 virtual void StartPostWriteValidation( 226 const base::FilePath& dest_platform_path, 227 const ResultCallback& result_callback) OVERRIDE { 228 // Post the result since a real validator must do work asynchronously. 229 base::MessageLoop::current()->PostTask( 230 FROM_HERE, base::Bind(result_callback, write_result_)); 231 } 232 233 private: 234 base::PlatformFileError result_; 235 base::PlatformFileError write_result_; 236 237 DISALLOW_COPY_AND_ASSIGN(TestCopyOrMoveFileValidator); 238 }; 239 240 Validity validity_; 241 242 DISALLOW_COPY_AND_ASSIGN(TestCopyOrMoveFileValidatorFactory); 243 }; 244 245 } // namespace 246 247 TEST(CopyOrMoveFileValidatorTest, NoValidatorWithinSameFSType) { 248 // Within a file system type, validation is not expected, so it should 249 // work for kWithValidatorType without a validator set. 250 CopyOrMoveFileValidatorTestHelper helper(GURL("http://foo"), 251 kWithValidatorType, 252 kWithValidatorType); 253 helper.SetUp(); 254 helper.CopyTest(base::PLATFORM_FILE_OK); 255 helper.MoveTest(base::PLATFORM_FILE_OK); 256 } 257 258 TEST(CopyOrMoveFileValidatorTest, MissingValidator) { 259 // Copying or moving into a kWithValidatorType requires a file 260 // validator. An error is expected if copy is attempted without a validator. 261 CopyOrMoveFileValidatorTestHelper helper(GURL("http://foo"), 262 kNoValidatorType, 263 kWithValidatorType); 264 helper.SetUp(); 265 helper.CopyTest(base::PLATFORM_FILE_ERROR_SECURITY); 266 helper.MoveTest(base::PLATFORM_FILE_ERROR_SECURITY); 267 } 268 269 TEST(CopyOrMoveFileValidatorTest, AcceptAll) { 270 CopyOrMoveFileValidatorTestHelper helper(GURL("http://foo"), 271 kNoValidatorType, 272 kWithValidatorType); 273 helper.SetUp(); 274 scoped_ptr<CopyOrMoveFileValidatorFactory> factory( 275 new TestCopyOrMoveFileValidatorFactory(VALID)); 276 helper.SetMediaCopyOrMoveFileValidatorFactory(factory.Pass()); 277 278 helper.CopyTest(base::PLATFORM_FILE_OK); 279 helper.MoveTest(base::PLATFORM_FILE_OK); 280 } 281 282 TEST(CopyOrMoveFileValidatorTest, AcceptNone) { 283 CopyOrMoveFileValidatorTestHelper helper(GURL("http://foo"), 284 kNoValidatorType, 285 kWithValidatorType); 286 helper.SetUp(); 287 scoped_ptr<CopyOrMoveFileValidatorFactory> factory( 288 new TestCopyOrMoveFileValidatorFactory(PRE_WRITE_INVALID)); 289 helper.SetMediaCopyOrMoveFileValidatorFactory(factory.Pass()); 290 291 helper.CopyTest(base::PLATFORM_FILE_ERROR_SECURITY); 292 helper.MoveTest(base::PLATFORM_FILE_ERROR_SECURITY); 293 } 294 295 TEST(CopyOrMoveFileValidatorTest, OverrideValidator) { 296 // Once set, you can not override the validator. 297 CopyOrMoveFileValidatorTestHelper helper(GURL("http://foo"), 298 kNoValidatorType, 299 kWithValidatorType); 300 helper.SetUp(); 301 scoped_ptr<CopyOrMoveFileValidatorFactory> reject_factory( 302 new TestCopyOrMoveFileValidatorFactory(PRE_WRITE_INVALID)); 303 helper.SetMediaCopyOrMoveFileValidatorFactory(reject_factory.Pass()); 304 305 scoped_ptr<CopyOrMoveFileValidatorFactory> accept_factory( 306 new TestCopyOrMoveFileValidatorFactory(VALID)); 307 helper.SetMediaCopyOrMoveFileValidatorFactory(accept_factory.Pass()); 308 309 helper.CopyTest(base::PLATFORM_FILE_ERROR_SECURITY); 310 helper.MoveTest(base::PLATFORM_FILE_ERROR_SECURITY); 311 } 312 313 TEST(CopyOrMoveFileValidatorTest, RejectPostWrite) { 314 CopyOrMoveFileValidatorTestHelper helper(GURL("http://foo"), 315 kNoValidatorType, 316 kWithValidatorType); 317 helper.SetUp(); 318 scoped_ptr<CopyOrMoveFileValidatorFactory> factory( 319 new TestCopyOrMoveFileValidatorFactory(POST_WRITE_INVALID)); 320 helper.SetMediaCopyOrMoveFileValidatorFactory(factory.Pass()); 321 322 helper.CopyTest(base::PLATFORM_FILE_ERROR_SECURITY); 323 helper.MoveTest(base::PLATFORM_FILE_ERROR_SECURITY); 324 } 325 326 } // namespace fileapi 327