| Index: chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc | 
| diff --git a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc | 
| index a1ede5ae806c2a7fc6ff060194af0160c728e56b..1d3b36064099dca3f9ba84c637ab7001cfc009da 100644 | 
| --- a/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc | 
| +++ b/chrome/browser/sync_file_system/local/local_file_sync_context_unittest.cc | 
| @@ -26,6 +26,7 @@ | 
| #include "webkit/browser/fileapi/file_system_context.h" | 
| #include "webkit/browser/fileapi/file_system_operation_runner.h" | 
| #include "webkit/browser/fileapi/isolated_context.h" | 
| +#include "webkit/common/blob/scoped_file.h" | 
|  | 
| #define FPL FILE_PATH_LITERAL | 
|  | 
| @@ -60,6 +61,7 @@ class LocalFileSyncContextTest : public testing::Test { | 
|  | 
| virtual void SetUp() OVERRIDE { | 
| RegisterSyncableFileSystem(); | 
| +    ASSERT_TRUE(dir_.CreateUniqueTempDir()); | 
|  | 
| ui_task_runner_ = base::MessageLoop::current()->message_loop_proxy(); | 
| io_task_runner_ = BrowserThread::GetMessageLoopProxyForThread( | 
| @@ -74,8 +76,10 @@ class LocalFileSyncContextTest : public testing::Test { | 
|  | 
| void StartPrepareForSync(FileSystemContext* file_system_context, | 
| const FileSystemURL& url, | 
| +                           LocalFileSyncContext::SyncMode sync_mode, | 
| SyncFileMetadata* metadata, | 
| -                           FileChangeList* changes) { | 
| +                           FileChangeList* changes, | 
| +                           webkit_blob::ScopedFile* snapshot) { | 
| ASSERT_TRUE(changes != NULL); | 
| ASSERT_FALSE(has_inflight_prepare_for_sync_); | 
| status_ = SYNC_STATUS_UNKNOWN; | 
| @@ -83,39 +87,49 @@ class LocalFileSyncContextTest : public testing::Test { | 
| sync_context_->PrepareForSync( | 
| file_system_context, | 
| url, | 
| -        LocalFileSyncContext::SYNC_EXCLUSIVE, | 
| +        sync_mode, | 
| base::Bind(&LocalFileSyncContextTest::DidPrepareForSync, | 
| -                   base::Unretained(this), metadata, changes)); | 
| +                   base::Unretained(this), metadata, changes, snapshot)); | 
| } | 
|  | 
| SyncStatusCode PrepareForSync(FileSystemContext* file_system_context, | 
| const FileSystemURL& url, | 
| +                                LocalFileSyncContext::SyncMode sync_mode, | 
| SyncFileMetadata* metadata, | 
| -                                FileChangeList* changes) { | 
| -    StartPrepareForSync(file_system_context, url, metadata, changes); | 
| +                                FileChangeList* changes, | 
| +                                webkit_blob::ScopedFile* snapshot) { | 
| +    StartPrepareForSync(file_system_context, url, sync_mode, | 
| +                        metadata, changes, snapshot); | 
| base::MessageLoop::current()->Run(); | 
| return status_; | 
| } | 
|  | 
| -  base::Closure GetPrepareForSyncClosure(FileSystemContext* file_system_context, | 
| -                                         const FileSystemURL& url, | 
| -                                         SyncFileMetadata* metadata, | 
| -                                         FileChangeList* changes) { | 
| +  base::Closure GetPrepareForSyncClosure( | 
| +      FileSystemContext* file_system_context, | 
| +      const FileSystemURL& url, | 
| +      LocalFileSyncContext::SyncMode sync_mode, | 
| +      SyncFileMetadata* metadata, | 
| +      FileChangeList* changes, | 
| +      webkit_blob::ScopedFile* snapshot) { | 
| return base::Bind(&LocalFileSyncContextTest::StartPrepareForSync, | 
| base::Unretained(this), | 
| base::Unretained(file_system_context), | 
| -                      url, metadata, changes); | 
| +                      url, sync_mode, metadata, changes, snapshot); | 
| } | 
|  | 
| void DidPrepareForSync(SyncFileMetadata* metadata_out, | 
| FileChangeList* changes_out, | 
| +                         webkit_blob::ScopedFile* snapshot_out, | 
| SyncStatusCode status, | 
| -                         const LocalFileSyncInfo& sync_file_info) { | 
| +                         const LocalFileSyncInfo& sync_file_info, | 
| +                         scoped_ptr<webkit_blob::ScopedFile> snapshot) { | 
| ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); | 
| has_inflight_prepare_for_sync_ = false; | 
| status_ = status; | 
| *metadata_out = sync_file_info.metadata; | 
| *changes_out = sync_file_info.changes; | 
| +    if (snapshot_out && snapshot) | 
| +      *snapshot_out = snapshot->Pass(); | 
| base::MessageLoop::current()->Quit(); | 
| } | 
|  | 
| @@ -131,7 +145,9 @@ class LocalFileSyncContextTest : public testing::Test { | 
| SyncFileMetadata metadata; | 
| FileChangeList changes; | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| -              PrepareForSync(file_system_context, url, &metadata, &changes)); | 
| +              PrepareForSync(file_system_context, url, | 
| +                             LocalFileSyncContext::SYNC_EXCLUSIVE, | 
| +                             &metadata, &changes, NULL)); | 
| EXPECT_EQ(expected_file_type, metadata.file_type); | 
|  | 
| status_ = SYNC_STATUS_UNKNOWN; | 
| @@ -206,7 +222,7 @@ class LocalFileSyncContextTest : public testing::Test { | 
| file_task_runner_.get()); | 
| file_system.SetUp(); | 
| sync_context_ = new LocalFileSyncContext( | 
| -        ui_task_runner_.get(), io_task_runner_.get()); | 
| +        dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| ASSERT_EQ(SYNC_STATUS_OK, | 
| file_system.MaybeInitializeFileSystemContext( | 
| sync_context_.get())); | 
| @@ -219,7 +235,7 @@ class LocalFileSyncContextTest : public testing::Test { | 
| FileChangeList changes; | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| PrepareForSync(file_system.file_system_context(), kFile, | 
| -                             &metadata, &changes)); | 
| +                             sync_mode, &metadata, &changes, NULL)); | 
| EXPECT_EQ(1U, changes.size()); | 
| EXPECT_TRUE(changes.list().back().IsFile()); | 
| EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); | 
| @@ -249,8 +265,73 @@ class LocalFileSyncContextTest : public testing::Test { | 
| file_system.TearDown(); | 
| } | 
|  | 
| +  void PrepareForSync_WriteDuringSync( | 
| +      LocalFileSyncContext::SyncMode sync_mode) { | 
| +    CannedSyncableFileSystem file_system(GURL(kOrigin1), | 
| +                                         io_task_runner_.get(), | 
| +                                         file_task_runner_.get()); | 
| +    file_system.SetUp(); | 
| +    sync_context_ = new LocalFileSyncContext( | 
| +        dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| +    ASSERT_EQ(SYNC_STATUS_OK, | 
| +              file_system.MaybeInitializeFileSystemContext( | 
| +                  sync_context_.get())); | 
| +    ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); | 
| + | 
| +    const FileSystemURL kFile(file_system.URL("file")); | 
| +    EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile)); | 
| + | 
| +    SyncFileMetadata metadata; | 
| +    FileChangeList changes; | 
| +    webkit_blob::ScopedFile snapshot; | 
| +    EXPECT_EQ(SYNC_STATUS_OK, | 
| +              PrepareForSync(file_system.file_system_context(), kFile, | 
| +                             sync_mode, &metadata, &changes, &snapshot)); | 
| +    EXPECT_EQ(1U, changes.size()); | 
| +    EXPECT_TRUE(changes.list().back().IsFile()); | 
| +    EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); | 
| + | 
| +    EXPECT_EQ(sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT, | 
| +              !snapshot.path().empty()); | 
| + | 
| +    // Tracker keeps same set of changes. | 
| +    file_system.GetChangesForURLInTracker(kFile, &changes); | 
| +    EXPECT_EQ(1U, changes.size()); | 
| +    EXPECT_TRUE(changes.list().back().IsFile()); | 
| +    EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); | 
| + | 
| +    StartModifyFileOnIOThread(&file_system, kFile); | 
| + | 
| +    if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) { | 
| +      // Write should succeed. | 
| +      EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); | 
| +    } else { | 
| +      base::MessageLoop::current()->RunUntilIdle(); | 
| +      EXPECT_FALSE(async_modify_finished_); | 
| +    } | 
| + | 
| +    SimulateFinishSync(file_system.file_system_context(), kFile, | 
| +                       SYNC_STATUS_OK); | 
| + | 
| +    EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); | 
| + | 
| +    // Sync succeeded, but the other change that was made during or | 
| +    // after sync is recorded. | 
| +    file_system.GetChangesForURLInTracker(kFile, &changes); | 
| +    EXPECT_EQ(1U, changes.size()); | 
| +    EXPECT_TRUE(changes.list().back().IsFile()); | 
| +    EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); | 
| + | 
| +    sync_context_->ShutdownOnUIThread(); | 
| +    sync_context_ = NULL; | 
| + | 
| +    file_system.TearDown(); | 
| +  } | 
| + | 
| ScopedEnableSyncFSDirectoryOperation enable_directory_operation_; | 
|  | 
| +  base::ScopedTempDir dir_; | 
| + | 
| // These need to remain until the very end. | 
| content::TestBrowserThreadBundle thread_bundle_; | 
|  | 
| @@ -267,8 +348,9 @@ class LocalFileSyncContextTest : public testing::Test { | 
| }; | 
|  | 
| TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) { | 
| -  sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +  sync_context_ = | 
| +      new LocalFileSyncContext( | 
| +          dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| sync_context_->ShutdownOnUIThread(); | 
| } | 
|  | 
| @@ -279,7 +361,7 @@ TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) { | 
| file_system.SetUp(); | 
|  | 
| sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +      dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
|  | 
| // Initializes file_system using |sync_context_|. | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| @@ -324,7 +406,7 @@ TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) { | 
| file_system2.SetUp(); | 
|  | 
| sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +      dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
|  | 
| // Initializes file_system1 and file_system2. | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| @@ -371,7 +453,8 @@ TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) { | 
| FileChangeList changes; | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| PrepareForSync(file_system1.file_system_context(), kURL1, | 
| -                           &metadata, &changes)); | 
| +                           LocalFileSyncContext::SYNC_EXCLUSIVE, | 
| +                           &metadata, &changes, NULL)); | 
| EXPECT_EQ(1U, changes.size()); | 
| EXPECT_TRUE(changes.list().back().IsFile()); | 
| EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); | 
| @@ -381,7 +464,8 @@ TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) { | 
| changes.clear(); | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| PrepareForSync(file_system2.file_system_context(), kURL2, | 
| -                           &metadata, &changes)); | 
| +                           LocalFileSyncContext::SYNC_EXCLUSIVE, | 
| +                           &metadata, &changes, NULL)); | 
| EXPECT_EQ(1U, changes.size()); | 
| EXPECT_FALSE(changes.list().back().IsFile()); | 
| EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); | 
| @@ -415,6 +499,14 @@ TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Snapshot) { | 
| SYNC_STATUS_FAILED); | 
| } | 
|  | 
| +TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Exclusive) { | 
| +  PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_EXCLUSIVE); | 
| +} | 
| + | 
| +TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Snapshot) { | 
| +  PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_SNAPSHOT); | 
| +} | 
| + | 
| // LocalFileSyncContextTest.PrepareSyncWhileWriting is flaky on android. | 
| // http://crbug.com/239793 | 
| #if defined(OS_ANDROID) | 
| @@ -428,7 +520,7 @@ TEST_F(LocalFileSyncContextTest, MAYBE_PrepareSyncWhileWriting) { | 
| file_task_runner_.get()); | 
| file_system.SetUp(); | 
| sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +      dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| EXPECT_EQ(SYNC_STATUS_OK, | 
| file_system.MaybeInitializeFileSystemContext(sync_context_.get())); | 
|  | 
| @@ -447,8 +539,9 @@ TEST_F(LocalFileSyncContextTest, MAYBE_PrepareSyncWhileWriting) { | 
| metadata.file_type = SYNC_FILE_TYPE_UNKNOWN; | 
| FileChangeList changes; | 
| EXPECT_EQ(SYNC_STATUS_FILE_BUSY, | 
| -            PrepareForSync(file_system.file_system_context(), | 
| -                           kURL1, &metadata, &changes)); | 
| +            PrepareForSync(file_system.file_system_context(), kURL1, | 
| +                           LocalFileSyncContext::SYNC_EXCLUSIVE, | 
| +                           &metadata, &changes, NULL)); | 
| EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type); | 
|  | 
| // Register PrepareForSync method to be invoked when kURL1 becomes | 
| @@ -457,8 +550,9 @@ TEST_F(LocalFileSyncContextTest, MAYBE_PrepareSyncWhileWriting) { | 
| metadata.file_type = SYNC_FILE_TYPE_UNKNOWN; | 
| changes.clear(); | 
| sync_context_->RegisterURLForWaitingSync( | 
| -      kURL1, GetPrepareForSyncClosure(file_system.file_system_context(), | 
| -                                      kURL1, &metadata, &changes)); | 
| +      kURL1, GetPrepareForSyncClosure(file_system.file_system_context(), kURL1, | 
| +                                      LocalFileSyncContext::SYNC_EXCLUSIVE, | 
| +                                      &metadata, &changes, NULL)); | 
|  | 
| // Wait for the completion. | 
| EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); | 
| @@ -488,7 +582,7 @@ TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion) { | 
| file_system.SetUp(); | 
|  | 
| sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +      dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| ASSERT_EQ(SYNC_STATUS_OK, | 
| file_system.MaybeInitializeFileSystemContext(sync_context_.get())); | 
| ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); | 
| @@ -577,7 +671,7 @@ TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate) { | 
| file_system.SetUp(); | 
|  | 
| sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +      dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| ASSERT_EQ(SYNC_STATUS_OK, | 
| file_system.MaybeInitializeFileSystemContext(sync_context_.get())); | 
| ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); | 
| @@ -726,7 +820,7 @@ TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate_NoParent) { | 
| file_system.SetUp(); | 
|  | 
| sync_context_ = new LocalFileSyncContext( | 
| -      ui_task_runner_.get(), io_task_runner_.get()); | 
| +      dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); | 
| ASSERT_EQ(SYNC_STATUS_OK, | 
| file_system.MaybeInitializeFileSystemContext(sync_context_.get())); | 
| ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); | 
|  |