diff options
author | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-26 10:56:06 +0000 |
---|---|---|
committer | kinuko@chromium.org <kinuko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-10-26 10:56:06 +0000 |
commit | 5e4b00e733b9cd37c035ad336f541aae7548efa5 (patch) | |
tree | 65bd5be28a06b22e16fd547f33cff6ad91f35352 /webkit/fileapi | |
parent | 7362421eb71391bd7078fe618f4baa4df5c57c99 (diff) | |
download | chromium_src-5e4b00e733b9cd37c035ad336f541aae7548efa5.zip chromium_src-5e4b00e733b9cd37c035ad336f541aae7548efa5.tar.gz chromium_src-5e4b00e733b9cd37c035ad336f541aae7548efa5.tar.bz2 |
Implement ApplyRemoteChange for Add/Update changes
BUG=156599
TEST=LocalFileSyncContext.ApplyRemoteChangeForAddOrUpdate
Review URL: https://codereview.chromium.org/11264038
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@164314 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/fileapi')
4 files changed, 217 insertions, 21 deletions
diff --git a/webkit/fileapi/syncable/canned_syncable_file_system.cc b/webkit/fileapi/syncable/canned_syncable_file_system.cc index 2f8a584..e5f49cd 100644 --- a/webkit/fileapi/syncable/canned_syncable_file_system.cc +++ b/webkit/fileapi/syncable/canned_syncable_file_system.cc @@ -10,6 +10,7 @@ #include "base/single_thread_task_runner.h" #include "base/task_runner_util.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/blob/mock_blob_url_request_context.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_operation_context.h" #include "webkit/fileapi/file_system_task_runners.h" @@ -23,6 +24,8 @@ using base::PlatformFileError; using quota::QuotaManager; +using webkit_blob::MockBlobURLRequestContext; +using webkit_blob::ScopedTextBlob; namespace fileapi { @@ -72,7 +75,17 @@ void VerifySameTaskRunner( class WriteHelper { public: WriteHelper() : bytes_written_(0) {} - ~WriteHelper() {} + WriteHelper(MockBlobURLRequestContext* request_context, + const GURL& blob_url, + const std::string& blob_data) + : bytes_written_(0), + request_context_(request_context), + blob_data_(new ScopedTextBlob(*request_context, blob_url, blob_data)) {} + + ~WriteHelper() { + if (request_context_) + MessageLoop::current()->DeleteSoon(FROM_HERE, request_context_.release()); + } void DidWrite(const base::Callback<void(int64)>& completion_callback, PlatformFileError error, int64 bytes, bool complete) { @@ -87,6 +100,10 @@ class WriteHelper { private: int64 bytes_written_; + scoped_ptr<MockBlobURLRequestContext> request_context_; + scoped_ptr<ScopedTextBlob> blob_data_; + + DISALLOW_COPY_AND_ASSIGN(WriteHelper); }; void DidGetUsageAndQuota(const quota::StatusCallback& callback, @@ -263,6 +280,15 @@ int64 CannedSyncableFileSystem::Write( base::Unretained(this), url_request_context, url, blob_url)); } +int64 CannedSyncableFileSystem::WriteString( + const FileSystemURL& url, const std::string& data) { + return RunOnThread<int64>( + io_task_runner_, + FROM_HERE, + base::Bind(&CannedSyncableFileSystem::DoWriteString, + base::Unretained(this), url, data)); +} + PlatformFileError CannedSyncableFileSystem::DeleteFileSystem() { EXPECT_TRUE(is_filesystem_set_up_); return RunOnThread<PlatformFileError>( @@ -355,6 +381,19 @@ void CannedSyncableFileSystem::DoWrite( base::Owned(helper), callback)); } +void CannedSyncableFileSystem::DoWriteString( + const FileSystemURL& url, + const std::string& data, + const WriteCallback& callback) { + MockBlobURLRequestContext* url_request_context( + new MockBlobURLRequestContext(file_system_context_)); + const GURL blob_url(std::string("blob:") + data); + WriteHelper* helper = new WriteHelper(url_request_context, blob_url, data); + NewOperation()->Write(url_request_context, url, blob_url, 0, + base::Bind(&WriteHelper::DidWrite, + base::Owned(helper), callback)); +} + void CannedSyncableFileSystem::DoGetUsageAndQuota( int64* usage, int64* quota, diff --git a/webkit/fileapi/syncable/canned_syncable_file_system.h b/webkit/fileapi/syncable/canned_syncable_file_system.h index 3a69328..b443853 100644 --- a/webkit/fileapi/syncable/canned_syncable_file_system.h +++ b/webkit/fileapi/syncable/canned_syncable_file_system.h @@ -94,6 +94,7 @@ class CannedSyncableFileSystem { // Returns the # of bytes written (>=0) or an error code (<0). int64 Write(net::URLRequestContext* url_request_context, const FileSystemURL& url, const GURL& blob_url); + int64 WriteString(const FileSystemURL& url, const std::string& data); // Purges the file system local storage. base::PlatformFileError DeleteFileSystem(); @@ -130,6 +131,9 @@ class CannedSyncableFileSystem { const FileSystemURL& url, const GURL& blob_url, const WriteCallback& callback); + void DoWriteString(const FileSystemURL& url, + const std::string& data, + const WriteCallback& callback); void DoGetUsageAndQuota(int64* usage, int64* quota, const quota::StatusCallback& callback); diff --git a/webkit/fileapi/syncable/local_file_sync_context.cc b/webkit/fileapi/syncable/local_file_sync_context.cc index ea12d42..9194eaa 100644 --- a/webkit/fileapi/syncable/local_file_sync_context.cc +++ b/webkit/fileapi/syncable/local_file_sync_context.cc @@ -130,6 +130,8 @@ void LocalFileSyncContext::ApplyRemoteChange( return; } DCHECK(io_task_runner_->RunsTasksOnCurrentThread()); + DCHECK(!sync_status()->IsWritable(url)); + DCHECK(!sync_status()->IsWriting(url)); LocalFileSystemOperation* operation = CreateFileSystemOperationForSync( file_system_context); DCHECK(operation); @@ -138,8 +140,19 @@ void LocalFileSyncContext::ApplyRemoteChange( this, callback); switch (change.change()) { case FileChange::FILE_CHANGE_ADD_OR_UPDATE: - // TODO(kinuko): implement. (crbug.com/156599) - NOTIMPLEMENTED(); + switch (change.file_type()) { + case FileChange::FILE_TYPE_FILE: + DCHECK(!local_path.empty()); + operation->CopyInForeignFile(local_path, url, operation_callback); + break; + case FileChange::FILE_TYPE_DIRECTORY: + operation->CreateDirectory( + url, false /* exclusive */, true /* recursive */, + operation_callback); + break; + case FileChange::FILE_TYPE_UNDETERMINED: + NOTREACHED() << "File type undetermined for ADD_OR_UPDATE change"; + } break; case FileChange::FILE_CHANGE_DELETE: operation->Remove(url, true /* recursive */, operation_callback); diff --git a/webkit/fileapi/syncable/local_file_sync_context_unittest.cc b/webkit/fileapi/syncable/local_file_sync_context_unittest.cc index 46e8437..0b61fd9 100644 --- a/webkit/fileapi/syncable/local_file_sync_context_unittest.cc +++ b/webkit/fileapi/syncable/local_file_sync_context_unittest.cc @@ -8,11 +8,13 @@ #include "base/bind.h" #include "base/file_path.h" +#include "base/file_util.h" #include "base/message_loop.h" #include "base/platform_file.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread.h" #include "testing/gtest/include/gtest/gtest.h" +#include "webkit/blob/mock_blob_url_request_context.h" #include "webkit/fileapi/file_system_context.h" #include "webkit/fileapi/file_system_operation.h" #include "webkit/fileapi/isolated_context.h" @@ -21,6 +23,8 @@ #include "webkit/fileapi/syncable/sync_status_code.h" #include "webkit/fileapi/syncable/syncable_file_system_util.h" +#define FPL FILE_PATH_LITERAL + // This tests LocalFileSyncContext behavior in multi-thread / // multi-file-system-context environment. // Basic combined tests (single-thread / single-file-system-context) @@ -59,24 +63,6 @@ class LocalFileSyncContextTest : public testing::Test { io_thread_->Stop(); } - SyncStatusCode ApplyRemoteChange(FileSystemContext* file_system_context, - const FileChange& change, - const FilePath& local_path, - const FileSystemURL& url) { - status_ = SYNC_STATUS_UNKNOWN; - sync_context_->ApplyRemoteChange( - file_system_context, change, local_path, url, - base::Bind(&LocalFileSyncContextTest::DidApplyRemoteChange, - base::Unretained(this))); - MessageLoop::current()->Run(); - return status_; - } - - void DidApplyRemoteChange(SyncStatusCode status) { - MessageLoop::current()->Quit(); - status_ = status; - } - void StartPrepareForSync(LocalFileSyncContext* sync_context, FileSystemContext* file_system_context, const FileSystemURL& url, @@ -121,6 +107,31 @@ class LocalFileSyncContextTest : public testing::Test { MessageLoop::current()->Quit(); } + SyncStatusCode ApplyRemoteChange(FileSystemContext* file_system_context, + const FileChange& change, + const FilePath& local_path, + const FileSystemURL& url) { + status_ = SYNC_STATUS_UNKNOWN; + + // First we should call PrepareForSync to disable writing. + FileChangeList changes; + StartPrepareForSync(sync_context_, file_system_context, url, &changes); + MessageLoop::current()->Run(); + EXPECT_EQ(SYNC_STATUS_OK, status_); + + sync_context_->ApplyRemoteChange( + file_system_context, change, local_path, url, + base::Bind(&LocalFileSyncContextTest::DidApplyRemoteChange, + base::Unretained(this))); + MessageLoop::current()->Run(); + return status_; + } + + void DidApplyRemoteChange(SyncStatusCode status) { + MessageLoop::current()->Quit(); + status_ = status; + } + void StartModifyFileOnIOThread(CannedSyncableFileSystem* file_system, const FileSystemURL& url) { async_modify_finished_ = false; @@ -428,4 +439,133 @@ TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion) { file_system.TearDown(); } +TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate) { + ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + CannedSyncableFileSystem file_system(GURL(kOrigin1), kServiceName, + io_task_runner_); + file_system.SetUp(); + + sync_context_ = new LocalFileSyncContext(ui_task_runner_, io_task_runner_); + ASSERT_EQ(SYNC_STATUS_OK, + file_system.MaybeInitializeFileSystemContext(sync_context_)); + ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); + + const FileSystemURL kFile1(file_system.URL("file1")); + const FileSystemURL kFile2(file_system.URL("file2")); + const FileSystemURL kDir(file_system.URL("dir")); + + const char kTestFileData0[] = "0123456789"; + const char kTestFileData1[] = "Lorem ipsum!"; + const char kTestFileData2[] = "This is sample test data."; + + // Create kFile1 and populate it with kTestFileData0. + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile1)); + EXPECT_EQ(static_cast<int64>(arraysize(kTestFileData0) - 1), + file_system.WriteString(kFile1, kTestFileData0)); + + // kFile2 and kDir are not there yet. + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, + file_system.FileExists(kFile2)); + EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, + file_system.DirectoryExists(kDir)); + + // file_system's change tracker must have recorded the creation. + std::vector<FileSystemURL> urls; + file_system.file_system_context()->change_tracker()->GetChangedURLs(&urls); + ASSERT_EQ(1U, urls.size()); + EXPECT_EQ(kFile1, urls[0]); + file_system.file_system_context()->change_tracker()->FinalizeSyncForURL( + urls[0]); + + // Prepare temporary files which represent the remote file data. + const FilePath kFilePath1(temp_dir.path().Append(FPL("file1"))); + const FilePath kFilePath2(temp_dir.path().Append(FPL("file2"))); + + ASSERT_EQ(static_cast<int>(arraysize(kTestFileData1) - 1), + file_util::WriteFile(kFilePath1, kTestFileData1, + arraysize(kTestFileData1) - 1)); + ASSERT_EQ(static_cast<int>(arraysize(kTestFileData2) - 1), + file_util::WriteFile(kFilePath2, kTestFileData2, + arraysize(kTestFileData2) - 1)); + + // Record the usage. + int64 usage = -1, new_usage = -1; + int64 quota = -1; + EXPECT_EQ(quota::kQuotaStatusOk, + file_system.GetUsageAndQuota(&usage, "a)); + + // Here in the local filesystem we have: + // * kFile1 with kTestFileData0 + // + // In the remote side let's assume we have: + // * kFile1 with kTestFileData1 + // * kFile2 with kTestFileData2 + // * kDir + // + // By calling ApplyChange's: + // * kFile1 will be updated to have kTestFileData1 + // * kFile2 will be created + // * kDir will be created + + // Apply the remote change to kFile1 (which will update the file). + FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE, + FileChange::FILE_TYPE_FILE); + EXPECT_EQ(SYNC_STATUS_OK, + ApplyRemoteChange(file_system.file_system_context(), + change, kFilePath1, kFile1)); + + // Check if the usage has been increased by (kTestFileData1 - kTestFileData0). + const int updated_size = + arraysize(kTestFileData1) - arraysize(kTestFileData0); + EXPECT_EQ(quota::kQuotaStatusOk, + file_system.GetUsageAndQuota(&new_usage, "a)); + EXPECT_EQ(updated_size, new_usage - usage); + + // Apply remote changes to kFile2 and kDir (should create a file and + // directory respectively). + change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, + FileChange::FILE_TYPE_FILE); + EXPECT_EQ(SYNC_STATUS_OK, + ApplyRemoteChange(file_system.file_system_context(), + change, kFilePath2, kFile2)); + + change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, + FileChange::FILE_TYPE_DIRECTORY); + EXPECT_EQ(SYNC_STATUS_OK, + ApplyRemoteChange(file_system.file_system_context(), + change, FilePath(), kDir)); + + // This should not happen, but calling ApplyRemoteChange + // with wrong file type will result in error. + change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, + FileChange::FILE_TYPE_FILE); + EXPECT_EQ(SYNC_FILE_ERROR_FAILED, + ApplyRemoteChange(file_system.file_system_context(), + change, kFilePath1, kDir)); + + // Creating a file/directory must have increased the usage more than + // the size of kTestFileData2. + new_usage = usage; + EXPECT_EQ(quota::kQuotaStatusOk, + file_system.GetUsageAndQuota(&new_usage, "a)); + EXPECT_GT(new_usage, + static_cast<int64>(usage + arraysize(kTestFileData2) - 1)); + + // The changes applied by ApplyRemoteChange should not be recorded in + // the change tracker. + urls.clear(); + file_system.file_system_context()->change_tracker()->GetChangedURLs(&urls); + EXPECT_TRUE(urls.empty()); + + // Make sure all three files/directory exist. + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile1)); + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile2)); + EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.DirectoryExists(kDir)); + + sync_context_->ShutdownOnUIThread(); + file_system.TearDown(); +} + } // namespace fileapi |