// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "webkit/fileapi/file_system_operation.h" #include "base/file_util.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "base/scoped_temp_dir.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/fileapi/file_system_callback_dispatcher.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_file_util.h" #include "webkit/fileapi/file_system_mount_point_provider.h" #include "webkit/fileapi/file_system_operation.h" #include "webkit/fileapi/file_system_quota_util.h" #include "webkit/fileapi/file_system_test_helper.h" #include "webkit/fileapi/file_system_util.h" #include "webkit/fileapi/local_file_util.h" #include "webkit/fileapi/quota_file_util.h" #include "webkit/quota/quota_manager.h" using quota::QuotaClient; using quota::QuotaManager; using quota::QuotaManagerProxy; using quota::StorageType; namespace fileapi { namespace { const int kFileOperationStatusNotSet = 1; class MockQuotaManager : public QuotaManager { public: MockQuotaManager(const FilePath& base_dir, const GURL& origin, StorageType type) : QuotaManager(false /* is_incognito */, base_dir, base::MessageLoopProxy::current(), base::MessageLoopProxy::current(), NULL), origin_(origin), type_(type), usage_(0), quota_(kint64max), accessed_(0) {} virtual void GetUsageAndQuota( const GURL& origin, quota::StorageType type, const GetUsageAndQuotaCallback& callback) OVERRIDE { EXPECT_EQ(origin_, origin); EXPECT_EQ(type_, type); callback.Run(quota::kQuotaStatusOk, usage_, quota_); } private: friend class MockQuotaManagerProxy; void SetQuota(const GURL& origin, StorageType type, int64 quota) { EXPECT_EQ(origin_, origin); EXPECT_EQ(type_, type); quota_ = quota; } void RecordStorageAccessed(const GURL& origin, StorageType type) { EXPECT_EQ(origin_, origin); EXPECT_EQ(type_, type); ++accessed_; } void UpdateUsage(const GURL& origin, StorageType type, int64 delta) { EXPECT_EQ(origin_, origin); EXPECT_EQ(type_, type); usage_ += delta; } const GURL& origin_; const StorageType type_; int64 usage_; int64 quota_; int accessed_; }; class MockQuotaManagerProxy : public QuotaManagerProxy { public: explicit MockQuotaManagerProxy(QuotaManager* quota_manager) : QuotaManagerProxy(quota_manager, base::MessageLoopProxy::current()), registered_client_(NULL) { } virtual ~MockQuotaManagerProxy() { EXPECT_FALSE(registered_client_); } virtual void RegisterClient(QuotaClient* client) OVERRIDE { EXPECT_FALSE(registered_client_); registered_client_ = client; } void SimulateQuotaManagerDestroyed() { if (registered_client_) { // We cannot call this in the destructor as the client (indirectly) // holds a refptr of the proxy. registered_client_->OnQuotaManagerDestroyed(); registered_client_ = NULL; } } // We don't mock them. virtual void NotifyOriginInUse(const GURL& origin) OVERRIDE {} virtual void NotifyOriginNoLongerInUse(const GURL& origin) OVERRIDE {} virtual void NotifyStorageAccessed(QuotaClient::ID client_id, const GURL& origin, StorageType type) OVERRIDE { mock_manager()->RecordStorageAccessed(origin, type); } virtual void NotifyStorageModified(QuotaClient::ID client_id, const GURL& origin, StorageType type, int64 delta) OVERRIDE { mock_manager()->UpdateUsage(origin, type, delta); } int storage_accessed_count() const { return mock_manager()->accessed_; } void SetQuota(const GURL& origin, StorageType type, int64 quota) { mock_manager()->SetQuota(origin, type, quota); } private: MockQuotaManager* mock_manager() const { return static_cast(quota_manager()); } QuotaClient* registered_client_; }; FilePath ASCIIToFilePath(const std::string& str) { return FilePath().AppendASCII(str); } } // namespace (anonymous) // Test class for FileSystemOperation. Note that this just tests low-level // operations but doesn't test OpenFileSystem. class FileSystemOperationTest : public testing::Test { public: FileSystemOperationTest() : status_(kFileOperationStatusNotSet), local_file_util_(new LocalFileUtil(QuotaFileUtil::CreateDefault())) { EXPECT_TRUE(base_.CreateUniqueTempDir()); } FileSystemOperation* operation(); void set_status(int status) { status_ = status; } int status() const { return status_; } void set_info(const base::PlatformFileInfo& info) { info_ = info; } const base::PlatformFileInfo& info() const { return info_; } void set_path(const FilePath& path) { path_ = path; } const FilePath& path() const { return path_; } void set_entries(const std::vector& entries) { entries_ = entries; } const std::vector& entries() const { return entries_; } virtual void SetUp(); virtual void TearDown(); protected: // Common temp base for nondestructive uses. ScopedTempDir base_; MockQuotaManagerProxy* quota_manager_proxy() { return static_cast(quota_manager_proxy_.get()); } GURL URLForPath(const FilePath& path) const { return test_helper_.GetURLForPath(path); } FilePath PlatformPath(const FilePath& virtual_path) { return test_helper_.GetLocalPath(virtual_path); } bool VirtualFileExists(const FilePath& virtual_path) { return file_util::PathExists(PlatformPath(virtual_path)) && !file_util::DirectoryExists(PlatformPath(virtual_path)); } bool VirtualDirectoryExists(const FilePath& virtual_path) { return file_util::DirectoryExists(PlatformPath(virtual_path)); } FilePath CreateVirtualDirectory(const char* virtual_path_string) { FilePath virtual_path(ASCIIToFilePath(virtual_path_string)); file_util::CreateDirectory(PlatformPath(virtual_path)); return virtual_path; } FilePath CreateVirtualDirectoryInDir(const char* virtual_path_string, const FilePath& virtual_dir_path) { FilePath virtual_path(virtual_dir_path.AppendASCII(virtual_path_string)); file_util::CreateDirectory(PlatformPath(virtual_path)); return virtual_path; } FilePath CreateVirtualTemporaryFileInDir(const FilePath& virtual_dir_path) { FilePath absolute_dir_path(PlatformPath(virtual_dir_path)); FilePath absolute_file_path; if (file_util::CreateTemporaryFileInDir(absolute_dir_path, &absolute_file_path)) return virtual_dir_path.Append(absolute_file_path.BaseName()); else return FilePath(); } FilePath CreateVirtualTemporaryDirInDir(const FilePath& virtual_dir_path) { FilePath absolute_parent_dir_path(PlatformPath(virtual_dir_path)); FilePath absolute_child_dir_path; if (file_util::CreateTemporaryDirInDir(absolute_parent_dir_path, FILE_PATH_LITERAL(""), &absolute_child_dir_path)) return virtual_dir_path.Append(absolute_child_dir_path.BaseName()); else return FilePath(); } FilePath CreateVirtualTemporaryDir() { return CreateVirtualTemporaryDirInDir(FilePath()); } FileSystemTestOriginHelper test_helper_; // For post-operation status. int status_; base::PlatformFileInfo info_; FilePath path_; std::vector entries_; private: scoped_ptr local_file_util_; scoped_refptr quota_manager_; scoped_refptr quota_manager_proxy_; DISALLOW_COPY_AND_ASSIGN(FileSystemOperationTest); }; namespace { class MockDispatcher : public FileSystemCallbackDispatcher { public: explicit MockDispatcher(FileSystemOperationTest* test) : test_(test) { } virtual void DidFail(base::PlatformFileError status) { test_->set_status(status); } virtual void DidSucceed() { test_->set_status(base::PLATFORM_FILE_OK); } virtual void DidReadMetadata( const base::PlatformFileInfo& info, const FilePath& platform_path) { test_->set_info(info); test_->set_path(platform_path); test_->set_status(base::PLATFORM_FILE_OK); } virtual void DidReadDirectory( const std::vector& entries, bool /* has_more */) { test_->set_entries(entries); } virtual void DidOpenFileSystem(const std::string&, const GURL&) { NOTREACHED(); } virtual void DidWrite(int64 bytes, bool complete) { NOTREACHED(); } private: FileSystemOperationTest* test_; }; } // namespace (anonymous) void FileSystemOperationTest::SetUp() { FilePath base_dir = base_.path().AppendASCII("filesystem"); quota_manager_ = new MockQuotaManager( base_dir, test_helper_.origin(), test_helper_.storage_type()); quota_manager_proxy_ = new MockQuotaManagerProxy(quota_manager_.get()); test_helper_.SetUp(base_dir, false /* incognito */, false /* unlimited quota */, quota_manager_proxy_.get(), local_file_util_.get()); } void FileSystemOperationTest::TearDown() { // Let the client go away before dropping a ref of the quota manager proxy. quota_manager_proxy()->SimulateQuotaManagerDestroyed(); quota_manager_ = NULL; quota_manager_proxy_ = NULL; test_helper_.TearDown(); } FileSystemOperation* FileSystemOperationTest::operation() { return test_helper_.NewOperation(new MockDispatcher(this)); } TEST_F(FileSystemOperationTest, TestMoveFailureSrcDoesntExist) { GURL src(URLForPath(FilePath(FILE_PATH_LITERAL("a")))); GURL dest(URLForPath(FilePath(FILE_PATH_LITERAL("b")))); operation()->Move(src, dest); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestMoveFailureContainsPath) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDirInDir(src_dir_path)); operation()->Move(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); } TEST_F(FileSystemOperationTest, TestMoveFailureSrcDirExistsDestFile) { // Src exists and is dir. Dest is a file. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(CreateVirtualTemporaryFileInDir(dest_dir_path)); operation()->Move(URLForPath(src_dir_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); } TEST_F(FileSystemOperationTest, TestMoveFailureSrcFileExistsDestNonEmptyDir) { // Src exists and is a directory. Dest is a non-empty directory. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath child_file_path(CreateVirtualTemporaryFileInDir(dest_dir_path)); operation()->Move(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status()); } TEST_F(FileSystemOperationTest, TestMoveFailureSrcFileExistsDestDir) { // Src exists and is a file. Dest is a directory. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); operation()->Move(URLForPath(src_file_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); } TEST_F(FileSystemOperationTest, TestMoveFailureDestParentDoesntExist) { // Dest. parent path does not exist. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath nonexisting_file = FilePath(FILE_PATH_LITERAL("NonexistingDir")). Append(FILE_PATH_LITERAL("NonexistingFile")); operation()->Move(URLForPath(src_dir_path), URLForPath(nonexisting_file)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestMoveSuccessSrcFileAndOverwrite) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(CreateVirtualTemporaryFileInDir(dest_dir_path)); operation()->Move(URLForPath(src_file_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualFileExists(dest_file_path)); // Move is considered 'write' access (for both side), and won't be counted // as read access. EXPECT_EQ(0, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestMoveSuccessSrcFileAndNew) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(dest_dir_path.Append(FILE_PATH_LITERAL("NewFile"))); operation()->Move(URLForPath(src_file_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualFileExists(dest_file_path)); } TEST_F(FileSystemOperationTest, TestMoveSuccessSrcDirAndOverwrite) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDir()); operation()->Move(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(VirtualDirectoryExists(src_dir_path)); // Make sure we've overwritten but not moved the source under the |dest_dir|. EXPECT_TRUE(VirtualDirectoryExists(dest_dir_path)); EXPECT_FALSE(VirtualDirectoryExists( dest_dir_path.Append(src_dir_path.BaseName()))); } TEST_F(FileSystemOperationTest, TestMoveSuccessSrcDirAndNew) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_parent_dir_path(CreateVirtualTemporaryDir()); FilePath dest_child_dir_path(dest_parent_dir_path. Append(FILE_PATH_LITERAL("NewDirectory"))); operation()->Move(URLForPath(src_dir_path), URLForPath(dest_child_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(VirtualDirectoryExists(src_dir_path)); EXPECT_TRUE(VirtualDirectoryExists(dest_child_dir_path)); } TEST_F(FileSystemOperationTest, TestMoveSuccessSrcDirRecursive) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath child_dir_path(CreateVirtualTemporaryDirInDir(src_dir_path)); FilePath grandchild_file_path( CreateVirtualTemporaryFileInDir(child_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); operation()->Move(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualDirectoryExists(dest_dir_path.Append( child_dir_path.BaseName()))); EXPECT_TRUE(VirtualFileExists(dest_dir_path.Append( child_dir_path.BaseName()).Append( grandchild_file_path.BaseName()))); } TEST_F(FileSystemOperationTest, TestCopyFailureSrcDoesntExist) { operation()->Copy(URLForPath(FilePath(FILE_PATH_LITERAL("a"))), URLForPath(FilePath(FILE_PATH_LITERAL("b")))); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestCopyFailureContainsPath) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDirInDir(src_dir_path)); operation()->Copy(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); } TEST_F(FileSystemOperationTest, TestCopyFailureSrcDirExistsDestFile) { // Src exists and is dir. Dest is a file. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(CreateVirtualTemporaryFileInDir(dest_dir_path)); operation()->Copy(URLForPath(src_dir_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); } TEST_F(FileSystemOperationTest, TestCopyFailureSrcFileExistsDestNonEmptyDir) { // Src exists and is a directory. Dest is a non-empty directory. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath child_file_path(CreateVirtualTemporaryFileInDir(dest_dir_path)); operation()->Copy(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status()); } TEST_F(FileSystemOperationTest, TestCopyFailureSrcFileExistsDestDir) { // Src exists and is a file. Dest is a directory. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); operation()->Copy(URLForPath(src_file_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_INVALID_OPERATION, status()); } TEST_F(FileSystemOperationTest, TestCopyFailureDestParentDoesntExist) { // Dest. parent path does not exist. FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath nonexisting_path = FilePath(FILE_PATH_LITERAL("DontExistDir")); file_util::EnsureEndsWithSeparator(&nonexisting_path); FilePath nonexisting_file_path(nonexisting_path.Append( FILE_PATH_LITERAL("DontExistFile"))); operation()->Copy(URLForPath(src_dir_path), URLForPath(nonexisting_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestCopyFailureByQuota) { base::PlatformFileInfo info; FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(dest_dir_path.Append(FILE_PATH_LITERAL("NewFile"))); quota_manager_proxy()->SetQuota(test_helper_.origin(), test_helper_.storage_type(), 11); operation()->Truncate(URLForPath(src_file_path), 6); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(src_file_path), &info)); EXPECT_EQ(6, info.size); operation()->Copy(URLForPath(src_file_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status()); EXPECT_FALSE(VirtualFileExists(dest_file_path)); } TEST_F(FileSystemOperationTest, TestCopySuccessSrcFileAndOverwrite) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(CreateVirtualTemporaryFileInDir(dest_dir_path)); operation()->Copy(URLForPath(src_file_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualFileExists(dest_file_path)); EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestCopySuccessSrcFileAndNew) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath src_file_path(CreateVirtualTemporaryFileInDir(src_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); FilePath dest_file_path(dest_dir_path.Append(FILE_PATH_LITERAL("NewFile"))); operation()->Copy(URLForPath(src_file_path), URLForPath(dest_file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualFileExists(dest_file_path)); EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestCopySuccessSrcDirAndOverwrite) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_dir_path(CreateVirtualTemporaryDir()); operation()->Copy(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); // Make sure we've overwritten but not copied the source under the |dest_dir|. EXPECT_TRUE(VirtualDirectoryExists(dest_dir_path)); EXPECT_FALSE(VirtualDirectoryExists( dest_dir_path.Append(src_dir_path.BaseName()))); EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestCopySuccessSrcDirAndNew) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath dest_parent_dir_path(CreateVirtualTemporaryDir()); FilePath dest_child_dir_path(dest_parent_dir_path. Append(FILE_PATH_LITERAL("NewDirectory"))); operation()->Copy(URLForPath(src_dir_path), URLForPath(dest_child_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualDirectoryExists(dest_child_dir_path)); EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestCopySuccessSrcDirRecursive) { FilePath src_dir_path(CreateVirtualTemporaryDir()); FilePath child_dir_path(CreateVirtualTemporaryDirInDir(src_dir_path)); FilePath grandchild_file_path( CreateVirtualTemporaryFileInDir(child_dir_path)); FilePath dest_dir_path(CreateVirtualTemporaryDir()); operation()->Copy(URLForPath(src_dir_path), URLForPath(dest_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualDirectoryExists(dest_dir_path.Append( child_dir_path.BaseName()))); EXPECT_TRUE(VirtualFileExists(dest_dir_path.Append( child_dir_path.BaseName()).Append( grandchild_file_path.BaseName()))); EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestCreateFileFailure) { // Already existing file and exclusive true. FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); operation()->CreateFile(URLForPath(file_path), true); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status()); } TEST_F(FileSystemOperationTest, TestCreateFileSuccessFileExists) { // Already existing file and exclusive false. FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); operation()->CreateFile(URLForPath(file_path), false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualFileExists(file_path)); } TEST_F(FileSystemOperationTest, TestCreateFileSuccessExclusive) { // File doesn't exist but exclusive is true. FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(dir_path.Append(FILE_PATH_LITERAL("FileDoesntExist"))); operation()->CreateFile(URLForPath(file_path), true); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualFileExists(file_path)); } TEST_F(FileSystemOperationTest, TestCreateFileSuccessFileDoesntExist) { // Non existing file. FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(dir_path.Append(FILE_PATH_LITERAL("FileDoesntExist"))); operation()->CreateFile(URLForPath(file_path), false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); } TEST_F(FileSystemOperationTest, TestCreateDirFailureDestParentDoesntExist) { // Dest. parent path does not exist. FilePath nonexisting_path(FilePath( FILE_PATH_LITERAL("DirDoesntExist"))); FilePath nonexisting_file_path(nonexisting_path.Append( FILE_PATH_LITERAL("FileDoesntExist"))); operation()->CreateDirectory( URLForPath(nonexisting_file_path), false, false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestCreateDirFailureDirExists) { // Exclusive and dir existing at path. FilePath src_dir_path(CreateVirtualTemporaryDir()); operation()->CreateDirectory(URLForPath(src_dir_path), true, false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status()); } TEST_F(FileSystemOperationTest, TestCreateDirFailureFileExists) { // Exclusive true and file existing at path. FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); operation()->CreateDirectory(URLForPath(file_path), true, false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_EXISTS, status()); } TEST_F(FileSystemOperationTest, TestCreateDirSuccess) { // Dir exists and exclusive is false. FilePath dir_path(CreateVirtualTemporaryDir()); operation()->CreateDirectory(URLForPath(dir_path), false, false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); // Dir doesn't exist. FilePath nonexisting_dir_path(FilePath( FILE_PATH_LITERAL("nonexistingdir"))); operation()->CreateDirectory( URLForPath(nonexisting_dir_path), false, false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualDirectoryExists(nonexisting_dir_path)); } TEST_F(FileSystemOperationTest, TestCreateDirSuccessExclusive) { // Dir doesn't exist. FilePath nonexisting_dir_path(FilePath( FILE_PATH_LITERAL("nonexistingdir"))); operation()->CreateDirectory( URLForPath(nonexisting_dir_path), true, false); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(VirtualDirectoryExists(nonexisting_dir_path)); } TEST_F(FileSystemOperationTest, TestExistsAndMetadataFailure) { FilePath nonexisting_dir_path(FilePath( FILE_PATH_LITERAL("nonexistingdir"))); operation()->GetMetadata(URLForPath(nonexisting_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); operation()->FileExists(URLForPath(nonexisting_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); file_util::EnsureEndsWithSeparator(&nonexisting_dir_path); operation()->DirectoryExists(URLForPath(nonexisting_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestExistsAndMetadataSuccess) { FilePath dir_path(CreateVirtualTemporaryDir()); int read_access = 0; operation()->DirectoryExists(URLForPath(dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); ++read_access; operation()->GetMetadata(URLForPath(dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(info().is_directory); EXPECT_EQ(PlatformPath(dir_path), path()); ++read_access; FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); operation()->FileExists(URLForPath(file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); ++read_access; operation()->GetMetadata(URLForPath(file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(info().is_directory); EXPECT_EQ(PlatformPath(file_path), path()); ++read_access; EXPECT_EQ(read_access, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestTypeMismatchErrors) { FilePath dir_path(CreateVirtualTemporaryDir()); operation()->FileExists(URLForPath(dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_FILE, status()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); ASSERT_FALSE(file_path.empty()); operation()->DirectoryExists(URLForPath(file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY, status()); } TEST_F(FileSystemOperationTest, TestReadDirFailure) { // Path doesn't exist FilePath nonexisting_dir_path(FilePath( FILE_PATH_LITERAL("NonExistingDir"))); file_util::EnsureEndsWithSeparator(&nonexisting_dir_path); operation()->ReadDirectory(URLForPath(nonexisting_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); // File exists. FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); operation()->ReadDirectory(URLForPath(file_path)); MessageLoop::current()->RunAllPending(); // TODO(kkanetkar) crbug.com/54309 to change the error code. EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); } TEST_F(FileSystemOperationTest, TestReadDirSuccess) { // parent_dir // | | // child_dir child_file // Verify reading parent_dir. FilePath parent_dir_path(CreateVirtualTemporaryDir()); FilePath child_file_path(CreateVirtualTemporaryFileInDir(parent_dir_path)); FilePath child_dir_path(CreateVirtualTemporaryDirInDir(parent_dir_path)); ASSERT_FALSE(child_dir_path.empty()); operation()->ReadDirectory(URLForPath(parent_dir_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(kFileOperationStatusNotSet, status()); EXPECT_EQ(2u, entries().size()); for (size_t i = 0; i < entries().size(); ++i) { if (entries()[i].is_directory) { EXPECT_EQ(child_dir_path.BaseName().value(), entries()[i].name); } else { EXPECT_EQ(child_file_path.BaseName().value(), entries()[i].name); } } EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestRemoveFailure) { // Path doesn't exist. FilePath nonexisting_path(FilePath( FILE_PATH_LITERAL("NonExistingDir"))); file_util::EnsureEndsWithSeparator(&nonexisting_path); operation()->Remove(URLForPath(nonexisting_path), false /* recursive */); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, status()); // It's an error to try to remove a non-empty directory if recursive flag // is false. // parent_dir // | | // child_dir child_file // Verify deleting parent_dir. FilePath parent_dir_path(CreateVirtualTemporaryDir()); FilePath child_file_path(CreateVirtualTemporaryFileInDir(parent_dir_path)); FilePath child_dir_path(CreateVirtualTemporaryDirInDir(parent_dir_path)); ASSERT_FALSE(child_dir_path.empty()); operation()->Remove(URLForPath(parent_dir_path), false /* recursive */); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_EMPTY, status()); } TEST_F(FileSystemOperationTest, TestRemoveSuccess) { FilePath empty_dir_path(CreateVirtualTemporaryDir()); EXPECT_TRUE(VirtualDirectoryExists(empty_dir_path)); operation()->Remove(URLForPath(empty_dir_path), false /* recursive */); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(VirtualDirectoryExists(empty_dir_path)); // Removing a non-empty directory with recursive flag == true should be ok. // parent_dir // | | // child_dir child_file // Verify deleting parent_dir. FilePath parent_dir_path(CreateVirtualTemporaryDir()); FilePath child_file_path(CreateVirtualTemporaryFileInDir(parent_dir_path)); FilePath child_dir_path(CreateVirtualTemporaryDirInDir(parent_dir_path)); ASSERT_FALSE(child_dir_path.empty()); operation()->Remove(URLForPath(parent_dir_path), true /* recursive */); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(VirtualDirectoryExists(parent_dir_path)); // Remove is not a 'read' access. EXPECT_EQ(0, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestTruncate) { FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); char test_data[] = "test data"; int data_size = static_cast(sizeof(test_data)); EXPECT_EQ(data_size, file_util::WriteFile(PlatformPath(file_path), test_data, data_size)); // Check that its length is the size of the data written. operation()->GetMetadata(URLForPath(file_path)); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_FALSE(info().is_directory); EXPECT_EQ(data_size, info().size); // Extend the file by truncating it. int length = 17; operation()->Truncate(URLForPath(file_path), length); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); // Check that its length is now 17 and that it's all zeroes after the test // data. base::PlatformFileInfo info; EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info)); EXPECT_EQ(length, info.size); char data[100]; EXPECT_EQ(length, file_util::ReadFile(PlatformPath(file_path), data, length)); for (int i = 0; i < length; ++i) { if (i < static_cast(sizeof(test_data))) EXPECT_EQ(test_data[i], data[i]); else EXPECT_EQ(0, data[i]); } // Shorten the file by truncating it. length = 3; operation()->Truncate(URLForPath(file_path), length); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); // Check that its length is now 3 and that it contains only bits of test data. EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info)); EXPECT_EQ(length, info.size); EXPECT_EQ(length, file_util::ReadFile(PlatformPath(file_path), data, length)); for (int i = 0; i < length; ++i) EXPECT_EQ(test_data[i], data[i]); // Truncate is not a 'read' access. (Here expected access count is 1 // since we made 1 read access for GetMetadata.) EXPECT_EQ(1, quota_manager_proxy()->storage_accessed_count()); } TEST_F(FileSystemOperationTest, TestTruncateFailureByQuota) { base::PlatformFileInfo info; FilePath dir_path(CreateVirtualTemporaryDir()); FilePath file_path(CreateVirtualTemporaryFileInDir(dir_path)); quota_manager_proxy()->SetQuota(test_helper_.origin(), test_helper_.storage_type(), 10); operation()->Truncate(URLForPath(file_path), 10); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info)); EXPECT_EQ(10, info.size); operation()->Truncate(URLForPath(file_path), 11); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_ERROR_NO_SPACE, status()); EXPECT_TRUE(file_util::GetFileInfo(PlatformPath(file_path), &info)); EXPECT_EQ(10, info.size); } TEST_F(FileSystemOperationTest, TestTouchFile) { FilePath file_path(CreateVirtualTemporaryFileInDir(FilePath())); FilePath platform_path = PlatformPath(file_path); base::PlatformFileInfo info; EXPECT_TRUE(file_util::GetFileInfo(platform_path, &info)); EXPECT_FALSE(info.is_directory); EXPECT_EQ(0, info.size); const base::Time last_modified = info.last_modified; const base::Time last_accessed = info.last_accessed; const base::Time new_modified_time = base::Time::UnixEpoch(); const base::Time new_accessed_time = new_modified_time + base::TimeDelta::FromHours(77);; ASSERT_NE(last_modified, new_modified_time); ASSERT_NE(last_accessed, new_accessed_time); operation()->TouchFile(URLForPath(file_path), new_accessed_time, new_modified_time); MessageLoop::current()->RunAllPending(); EXPECT_EQ(base::PLATFORM_FILE_OK, status()); EXPECT_TRUE(file_util::GetFileInfo(platform_path, &info)); // We compare as time_t here to lower our resolution, to avoid false // negatives caused by conversion to the local filesystem's native // representation and back. EXPECT_EQ(new_modified_time.ToTimeT(), info.last_modified.ToTimeT()); EXPECT_EQ(new_accessed_time.ToTimeT(), info.last_accessed.ToTimeT()); } } // namespace fileapi