Home | History | Annotate | Download | only in local
      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 "chrome/browser/sync_file_system/local/local_file_sync_context.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/bind.h"
     10 #include "base/bind_helpers.h"
     11 #include "base/file_util.h"
     12 #include "base/files/file_path.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/stl_util.h"
     15 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
     16 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
     17 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
     18 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
     19 #include "chrome/browser/sync_file_system/sync_status_code.h"
     20 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
     21 #include "content/public/browser/browser_thread.h"
     22 #include "content/public/test/mock_blob_url_request_context.h"
     23 #include "content/public/test/test_browser_thread_bundle.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
     26 #include "third_party/leveldatabase/src/include/leveldb/env.h"
     27 #include "webkit/browser/fileapi/file_system_context.h"
     28 #include "webkit/browser/fileapi/file_system_operation_runner.h"
     29 #include "webkit/browser/fileapi/isolated_context.h"
     30 #include "webkit/common/blob/scoped_file.h"
     31 
     32 #define FPL FILE_PATH_LITERAL
     33 
     34 using content::BrowserThread;
     35 using fileapi::FileSystemContext;
     36 using fileapi::FileSystemURL;
     37 using fileapi::FileSystemURLSet;
     38 
     39 // This tests LocalFileSyncContext behavior in multi-thread /
     40 // multi-file-system-context environment.
     41 // Basic combined tests (single-thread / single-file-system-context)
     42 // that involve LocalFileSyncContext are also in
     43 // syncable_file_system_unittests.cc.
     44 
     45 namespace sync_file_system {
     46 
     47 namespace {
     48 const char kOrigin1[] = "http://example.com";
     49 const char kOrigin2[] = "http://chromium.org";
     50 }
     51 
     52 class LocalFileSyncContextTest : public testing::Test {
     53  protected:
     54   LocalFileSyncContextTest()
     55       : thread_bundle_(
     56             content::TestBrowserThreadBundle::REAL_FILE_THREAD |
     57             content::TestBrowserThreadBundle::REAL_IO_THREAD),
     58         status_(SYNC_FILE_ERROR_FAILED),
     59         file_error_(base::File::FILE_ERROR_FAILED),
     60         async_modify_finished_(false),
     61         has_inflight_prepare_for_sync_(false) {}
     62 
     63   virtual void SetUp() OVERRIDE {
     64     RegisterSyncableFileSystem();
     65     ASSERT_TRUE(dir_.CreateUniqueTempDir());
     66     in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
     67 
     68     ui_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
     69     io_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
     70         BrowserThread::IO);
     71     file_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
     72         BrowserThread::IO);
     73   }
     74 
     75   virtual void TearDown() OVERRIDE {
     76     RevokeSyncableFileSystem();
     77   }
     78 
     79   void StartPrepareForSync(FileSystemContext* file_system_context,
     80                            const FileSystemURL& url,
     81                            LocalFileSyncContext::SyncMode sync_mode,
     82                            SyncFileMetadata* metadata,
     83                            FileChangeList* changes,
     84                            webkit_blob::ScopedFile* snapshot) {
     85     ASSERT_TRUE(changes != NULL);
     86     ASSERT_FALSE(has_inflight_prepare_for_sync_);
     87     status_ = SYNC_STATUS_UNKNOWN;
     88     has_inflight_prepare_for_sync_ = true;
     89     sync_context_->PrepareForSync(
     90         file_system_context,
     91         url,
     92         sync_mode,
     93         base::Bind(&LocalFileSyncContextTest::DidPrepareForSync,
     94                    base::Unretained(this), metadata, changes, snapshot));
     95   }
     96 
     97   SyncStatusCode PrepareForSync(FileSystemContext* file_system_context,
     98                                 const FileSystemURL& url,
     99                                 LocalFileSyncContext::SyncMode sync_mode,
    100                                 SyncFileMetadata* metadata,
    101                                 FileChangeList* changes,
    102                                 webkit_blob::ScopedFile* snapshot) {
    103     StartPrepareForSync(file_system_context, url, sync_mode,
    104                         metadata, changes, snapshot);
    105     base::MessageLoop::current()->Run();
    106     return status_;
    107   }
    108 
    109   base::Closure GetPrepareForSyncClosure(
    110       FileSystemContext* file_system_context,
    111       const FileSystemURL& url,
    112       LocalFileSyncContext::SyncMode sync_mode,
    113       SyncFileMetadata* metadata,
    114       FileChangeList* changes,
    115       webkit_blob::ScopedFile* snapshot) {
    116     return base::Bind(&LocalFileSyncContextTest::StartPrepareForSync,
    117                       base::Unretained(this),
    118                       base::Unretained(file_system_context),
    119                       url, sync_mode, metadata, changes, snapshot);
    120   }
    121 
    122   void DidPrepareForSync(SyncFileMetadata* metadata_out,
    123                          FileChangeList* changes_out,
    124                          webkit_blob::ScopedFile* snapshot_out,
    125                          SyncStatusCode status,
    126                          const LocalFileSyncInfo& sync_file_info,
    127                          webkit_blob::ScopedFile snapshot) {
    128     ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
    129     has_inflight_prepare_for_sync_ = false;
    130     status_ = status;
    131     *metadata_out = sync_file_info.metadata;
    132     *changes_out = sync_file_info.changes;
    133     if (snapshot_out)
    134       *snapshot_out = snapshot.Pass();
    135     base::MessageLoop::current()->Quit();
    136   }
    137 
    138   SyncStatusCode ApplyRemoteChange(FileSystemContext* file_system_context,
    139                                    const FileChange& change,
    140                                    const base::FilePath& local_path,
    141                                    const FileSystemURL& url,
    142                                    SyncFileType expected_file_type) {
    143     SCOPED_TRACE(testing::Message() << "ApplyChange for " <<
    144                  url.DebugString());
    145 
    146     // First we should call PrepareForSync to disable writing.
    147     SyncFileMetadata metadata;
    148     FileChangeList changes;
    149     EXPECT_EQ(SYNC_STATUS_OK,
    150               PrepareForSync(file_system_context, url,
    151                              LocalFileSyncContext::SYNC_EXCLUSIVE,
    152                              &metadata, &changes, NULL));
    153     EXPECT_EQ(expected_file_type, metadata.file_type);
    154 
    155     status_ = SYNC_STATUS_UNKNOWN;
    156     sync_context_->ApplyRemoteChange(
    157         file_system_context, change, local_path, url,
    158         base::Bind(&LocalFileSyncContextTest::DidApplyRemoteChange,
    159                    base::Unretained(this),
    160                    make_scoped_refptr(file_system_context), url));
    161     base::MessageLoop::current()->Run();
    162     return status_;
    163   }
    164 
    165   void DidApplyRemoteChange(FileSystemContext* file_system_context,
    166                             const FileSystemURL& url,
    167                             SyncStatusCode status) {
    168     status_ = status;
    169     sync_context_->FinalizeExclusiveSync(
    170         file_system_context, url,
    171         status == SYNC_STATUS_OK /* clear_local_changes */,
    172         base::MessageLoop::QuitClosure());
    173   }
    174 
    175   void StartModifyFileOnIOThread(CannedSyncableFileSystem* file_system,
    176                                  const FileSystemURL& url) {
    177     ASSERT_TRUE(file_system != NULL);
    178     if (!io_task_runner_->RunsTasksOnCurrentThread()) {
    179       async_modify_finished_ = false;
    180       ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
    181       io_task_runner_->PostTask(
    182           FROM_HERE,
    183           base::Bind(&LocalFileSyncContextTest::StartModifyFileOnIOThread,
    184                      base::Unretained(this), file_system, url));
    185       return;
    186     }
    187     ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
    188     file_error_ = base::File::FILE_ERROR_FAILED;
    189     file_system->operation_runner()->Truncate(
    190         url, 1, base::Bind(&LocalFileSyncContextTest::DidModifyFile,
    191                            base::Unretained(this)));
    192   }
    193 
    194   base::File::Error WaitUntilModifyFileIsDone() {
    195     while (!async_modify_finished_)
    196       base::MessageLoop::current()->RunUntilIdle();
    197     return file_error_;
    198   }
    199 
    200   void DidModifyFile(base::File::Error error) {
    201     if (!ui_task_runner_->RunsTasksOnCurrentThread()) {
    202       ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
    203       ui_task_runner_->PostTask(
    204           FROM_HERE,
    205           base::Bind(&LocalFileSyncContextTest::DidModifyFile,
    206                      base::Unretained(this), error));
    207       return;
    208     }
    209     ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
    210     file_error_ = error;
    211     async_modify_finished_ = true;
    212   }
    213 
    214   void SimulateFinishSync(FileSystemContext* file_system_context,
    215                           const FileSystemURL& url,
    216                           SyncStatusCode status,
    217                           LocalFileSyncContext::SyncMode sync_mode) {
    218     if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) {
    219       sync_context_->FinalizeSnapshotSync(
    220           file_system_context, url, status,
    221           base::Bind(&base::DoNothing));
    222     } else {
    223       sync_context_->FinalizeExclusiveSync(
    224           file_system_context, url,
    225           status == SYNC_STATUS_OK /* clear_local_changes */,
    226           base::Bind(&base::DoNothing));
    227     }
    228   }
    229 
    230   void PrepareForSync_Basic(LocalFileSyncContext::SyncMode sync_mode,
    231                             SyncStatusCode simulate_sync_finish_status) {
    232     CannedSyncableFileSystem file_system(GURL(kOrigin1),
    233                                          in_memory_env_.get(),
    234                                          io_task_runner_.get(),
    235                                          file_task_runner_.get());
    236     file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    237     sync_context_ = new LocalFileSyncContext(
    238         dir_.path(), in_memory_env_.get(),
    239         ui_task_runner_.get(), io_task_runner_.get());
    240     ASSERT_EQ(SYNC_STATUS_OK,
    241               file_system.MaybeInitializeFileSystemContext(
    242                   sync_context_.get()));
    243     ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    244 
    245     const FileSystemURL kFile(file_system.URL("file"));
    246     EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
    247 
    248     SyncFileMetadata metadata;
    249     FileChangeList changes;
    250     EXPECT_EQ(SYNC_STATUS_OK,
    251               PrepareForSync(file_system.file_system_context(), kFile,
    252                              sync_mode, &metadata, &changes, NULL));
    253     EXPECT_EQ(1U, changes.size());
    254     EXPECT_TRUE(changes.list().back().IsFile());
    255     EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    256 
    257     // We should see the same set of changes.
    258     file_system.GetChangesForURLInTracker(kFile, &changes);
    259     EXPECT_EQ(1U, changes.size());
    260     EXPECT_TRUE(changes.list().back().IsFile());
    261     EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    262 
    263     SimulateFinishSync(file_system.file_system_context(), kFile,
    264                        simulate_sync_finish_status, sync_mode);
    265 
    266     file_system.GetChangesForURLInTracker(kFile, &changes);
    267     if (simulate_sync_finish_status == SYNC_STATUS_OK) {
    268       // The change's cleared.
    269       EXPECT_TRUE(changes.empty());
    270     } else {
    271       EXPECT_EQ(1U, changes.size());
    272       EXPECT_TRUE(changes.list().back().IsFile());
    273       EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    274     }
    275 
    276     sync_context_->ShutdownOnUIThread();
    277     sync_context_ = NULL;
    278 
    279     file_system.TearDown();
    280   }
    281 
    282   void PrepareForSync_WriteDuringSync(
    283       LocalFileSyncContext::SyncMode sync_mode) {
    284     CannedSyncableFileSystem file_system(GURL(kOrigin1),
    285                                          in_memory_env_.get(),
    286                                          io_task_runner_.get(),
    287                                          file_task_runner_.get());
    288     file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    289     sync_context_ = new LocalFileSyncContext(
    290         dir_.path(), in_memory_env_.get(),
    291         ui_task_runner_.get(), io_task_runner_.get());
    292     ASSERT_EQ(SYNC_STATUS_OK,
    293               file_system.MaybeInitializeFileSystemContext(
    294                   sync_context_.get()));
    295     ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    296 
    297     const FileSystemURL kFile(file_system.URL("file"));
    298     EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
    299 
    300     SyncFileMetadata metadata;
    301     FileChangeList changes;
    302     webkit_blob::ScopedFile snapshot;
    303     EXPECT_EQ(SYNC_STATUS_OK,
    304               PrepareForSync(file_system.file_system_context(), kFile,
    305                              sync_mode, &metadata, &changes, &snapshot));
    306     EXPECT_EQ(1U, changes.size());
    307     EXPECT_TRUE(changes.list().back().IsFile());
    308     EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    309 
    310     EXPECT_EQ(sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT,
    311               !snapshot.path().empty());
    312 
    313     // Tracker keeps same set of changes.
    314     file_system.GetChangesForURLInTracker(kFile, &changes);
    315     EXPECT_EQ(1U, changes.size());
    316     EXPECT_TRUE(changes.list().back().IsFile());
    317     EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    318 
    319     StartModifyFileOnIOThread(&file_system, kFile);
    320 
    321     if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) {
    322       // Write should succeed.
    323       EXPECT_EQ(base::File::FILE_OK, WaitUntilModifyFileIsDone());
    324     } else {
    325       base::MessageLoop::current()->RunUntilIdle();
    326       EXPECT_FALSE(async_modify_finished_);
    327     }
    328 
    329     SimulateFinishSync(file_system.file_system_context(), kFile,
    330                        SYNC_STATUS_OK, sync_mode);
    331 
    332     EXPECT_EQ(base::File::FILE_OK, WaitUntilModifyFileIsDone());
    333 
    334     // Sync succeeded, but the other change that was made during or
    335     // after sync is recorded.
    336     file_system.GetChangesForURLInTracker(kFile, &changes);
    337     EXPECT_EQ(1U, changes.size());
    338     EXPECT_TRUE(changes.list().back().IsFile());
    339     EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    340 
    341     sync_context_->ShutdownOnUIThread();
    342     sync_context_ = NULL;
    343 
    344     file_system.TearDown();
    345   }
    346 
    347   ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
    348 
    349   base::ScopedTempDir dir_;
    350   scoped_ptr<leveldb::Env> in_memory_env_;
    351 
    352   // These need to remain until the very end.
    353   content::TestBrowserThreadBundle thread_bundle_;
    354 
    355   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
    356   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
    357   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
    358 
    359   scoped_refptr<LocalFileSyncContext> sync_context_;
    360 
    361   SyncStatusCode status_;
    362   base::File::Error file_error_;
    363   bool async_modify_finished_;
    364   bool has_inflight_prepare_for_sync_;
    365 };
    366 
    367 TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) {
    368   sync_context_ =
    369       new LocalFileSyncContext(
    370           dir_.path(), in_memory_env_.get(),
    371           ui_task_runner_.get(), io_task_runner_.get());
    372   sync_context_->ShutdownOnUIThread();
    373 }
    374 
    375 TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) {
    376   CannedSyncableFileSystem file_system(GURL(kOrigin1),
    377                                        in_memory_env_.get(),
    378                                        io_task_runner_.get(),
    379                                        file_task_runner_.get());
    380   file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    381 
    382   sync_context_ = new LocalFileSyncContext(
    383       dir_.path(), in_memory_env_.get(),
    384       ui_task_runner_.get(), io_task_runner_.get());
    385 
    386   // Initializes file_system using |sync_context_|.
    387   EXPECT_EQ(SYNC_STATUS_OK,
    388             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    389 
    390   // Make sure everything's set up for file_system to be able to handle
    391   // syncable file system operations.
    392   EXPECT_TRUE(file_system.backend()->sync_context() != NULL);
    393   EXPECT_TRUE(file_system.backend()->change_tracker() != NULL);
    394   EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context());
    395 
    396   // Calling MaybeInitialize for the same context multiple times must be ok.
    397   EXPECT_EQ(SYNC_STATUS_OK,
    398             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    399   EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context());
    400 
    401   // Opens the file_system, perform some operation and see if the change tracker
    402   // correctly captures the change.
    403   EXPECT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    404 
    405   const FileSystemURL kURL(file_system.URL("foo"));
    406   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kURL));
    407 
    408   FileSystemURLSet urls;
    409   file_system.GetChangedURLsInTracker(&urls);
    410   ASSERT_EQ(1U, urls.size());
    411   EXPECT_TRUE(ContainsKey(urls, kURL));
    412 
    413   // Finishing the test.
    414   sync_context_->ShutdownOnUIThread();
    415   file_system.TearDown();
    416 }
    417 
    418 TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) {
    419   CannedSyncableFileSystem file_system1(GURL(kOrigin1),
    420                                         in_memory_env_.get(),
    421                                         io_task_runner_.get(),
    422                                         file_task_runner_.get());
    423   CannedSyncableFileSystem file_system2(GURL(kOrigin2),
    424                                         in_memory_env_.get(),
    425                                         io_task_runner_.get(),
    426                                         file_task_runner_.get());
    427   file_system1.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    428   file_system2.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    429 
    430   sync_context_ = new LocalFileSyncContext(
    431       dir_.path(), in_memory_env_.get(),
    432       ui_task_runner_.get(), io_task_runner_.get());
    433 
    434   // Initializes file_system1 and file_system2.
    435   EXPECT_EQ(SYNC_STATUS_OK,
    436             file_system1.MaybeInitializeFileSystemContext(sync_context_.get()));
    437   EXPECT_EQ(SYNC_STATUS_OK,
    438             file_system2.MaybeInitializeFileSystemContext(sync_context_.get()));
    439 
    440   EXPECT_EQ(base::File::FILE_OK, file_system1.OpenFileSystem());
    441   EXPECT_EQ(base::File::FILE_OK, file_system2.OpenFileSystem());
    442 
    443   const FileSystemURL kURL1(file_system1.URL("foo"));
    444   const FileSystemURL kURL2(file_system2.URL("bar"));
    445 
    446   // Creates a file in file_system1.
    447   EXPECT_EQ(base::File::FILE_OK, file_system1.CreateFile(kURL1));
    448 
    449   // file_system1's tracker must have recorded the change.
    450   FileSystemURLSet urls;
    451   file_system1.GetChangedURLsInTracker(&urls);
    452   ASSERT_EQ(1U, urls.size());
    453   EXPECT_TRUE(ContainsKey(urls, kURL1));
    454 
    455   // file_system1's tracker must have no change.
    456   urls.clear();
    457   file_system2.GetChangedURLsInTracker(&urls);
    458   ASSERT_TRUE(urls.empty());
    459 
    460   // Creates a directory in file_system2.
    461   EXPECT_EQ(base::File::FILE_OK, file_system2.CreateDirectory(kURL2));
    462 
    463   // file_system1's tracker must have the change for kURL1 as before.
    464   urls.clear();
    465   file_system1.GetChangedURLsInTracker(&urls);
    466   ASSERT_EQ(1U, urls.size());
    467   EXPECT_TRUE(ContainsKey(urls, kURL1));
    468 
    469   // file_system2's tracker now must have the change for kURL2.
    470   urls.clear();
    471   file_system2.GetChangedURLsInTracker(&urls);
    472   ASSERT_EQ(1U, urls.size());
    473   EXPECT_TRUE(ContainsKey(urls, kURL2));
    474 
    475   SyncFileMetadata metadata;
    476   FileChangeList changes;
    477   EXPECT_EQ(SYNC_STATUS_OK,
    478             PrepareForSync(file_system1.file_system_context(), kURL1,
    479                            LocalFileSyncContext::SYNC_EXCLUSIVE,
    480                            &metadata, &changes, NULL));
    481   EXPECT_EQ(1U, changes.size());
    482   EXPECT_TRUE(changes.list().back().IsFile());
    483   EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    484   EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
    485   EXPECT_EQ(0, metadata.size);
    486 
    487   changes.clear();
    488   EXPECT_EQ(SYNC_STATUS_OK,
    489             PrepareForSync(file_system2.file_system_context(), kURL2,
    490                            LocalFileSyncContext::SYNC_EXCLUSIVE,
    491                            &metadata, &changes, NULL));
    492   EXPECT_EQ(1U, changes.size());
    493   EXPECT_FALSE(changes.list().back().IsFile());
    494   EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    495   EXPECT_EQ(SYNC_FILE_TYPE_DIRECTORY, metadata.file_type);
    496   EXPECT_EQ(0, metadata.size);
    497 
    498   sync_context_->ShutdownOnUIThread();
    499   sync_context_ = NULL;
    500 
    501   file_system1.TearDown();
    502   file_system2.TearDown();
    503 }
    504 
    505 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Exclusive) {
    506   PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
    507                        SYNC_STATUS_OK);
    508 }
    509 
    510 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Snapshot) {
    511   PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
    512                        SYNC_STATUS_OK);
    513 }
    514 
    515 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Exclusive) {
    516   PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
    517                        SYNC_STATUS_FAILED);
    518 }
    519 
    520 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Snapshot) {
    521   PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
    522                        SYNC_STATUS_FAILED);
    523 }
    524 
    525 TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Exclusive) {
    526   PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_EXCLUSIVE);
    527 }
    528 
    529 TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Snapshot) {
    530   PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_SNAPSHOT);
    531 }
    532 
    533 // LocalFileSyncContextTest.PrepareSyncWhileWriting is flaky on android.
    534 // http://crbug.com/239793
    535 // It is also flaky on the TSAN v2 bots, and hangs other bots.
    536 // http://crbug.com/305905.
    537 TEST_F(LocalFileSyncContextTest, DISABLED_PrepareSyncWhileWriting) {
    538   CannedSyncableFileSystem file_system(GURL(kOrigin1),
    539                                        in_memory_env_.get(),
    540                                        io_task_runner_.get(),
    541                                        file_task_runner_.get());
    542   file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    543   sync_context_ = new LocalFileSyncContext(
    544       dir_.path(), in_memory_env_.get(),
    545       ui_task_runner_.get(), io_task_runner_.get());
    546   EXPECT_EQ(SYNC_STATUS_OK,
    547             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    548 
    549   EXPECT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    550 
    551   const FileSystemURL kURL1(file_system.URL("foo"));
    552 
    553   // Creates a file in file_system.
    554   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kURL1));
    555 
    556   // Kick file write on IO thread.
    557   StartModifyFileOnIOThread(&file_system, kURL1);
    558 
    559   // Until the operation finishes PrepareForSync should return BUSY error.
    560   SyncFileMetadata metadata;
    561   metadata.file_type = SYNC_FILE_TYPE_UNKNOWN;
    562   FileChangeList changes;
    563   EXPECT_EQ(SYNC_STATUS_FILE_BUSY,
    564             PrepareForSync(file_system.file_system_context(), kURL1,
    565                            LocalFileSyncContext::SYNC_EXCLUSIVE,
    566                            &metadata, &changes, NULL));
    567   EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
    568 
    569   // Register PrepareForSync method to be invoked when kURL1 becomes
    570   // syncable. (Actually this may be done after all operations are done
    571   // on IO thread in this test.)
    572   metadata.file_type = SYNC_FILE_TYPE_UNKNOWN;
    573   changes.clear();
    574   sync_context_->RegisterURLForWaitingSync(
    575       kURL1, GetPrepareForSyncClosure(file_system.file_system_context(), kURL1,
    576                                       LocalFileSyncContext::SYNC_EXCLUSIVE,
    577                                       &metadata, &changes, NULL));
    578 
    579   // Wait for the completion.
    580   EXPECT_EQ(base::File::FILE_OK, WaitUntilModifyFileIsDone());
    581 
    582   // The PrepareForSync must have been started; wait until DidPrepareForSync
    583   // is done.
    584   base::MessageLoop::current()->Run();
    585   ASSERT_FALSE(has_inflight_prepare_for_sync_);
    586 
    587   // Now PrepareForSync should have run and returned OK.
    588   EXPECT_EQ(SYNC_STATUS_OK, status_);
    589   EXPECT_EQ(1U, changes.size());
    590   EXPECT_TRUE(changes.list().back().IsFile());
    591   EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
    592   EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
    593   EXPECT_EQ(1, metadata.size);
    594 
    595   sync_context_->ShutdownOnUIThread();
    596   sync_context_ = NULL;
    597   file_system.TearDown();
    598 }
    599 
    600 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion) {
    601   CannedSyncableFileSystem file_system(GURL(kOrigin1),
    602                                        in_memory_env_.get(),
    603                                        io_task_runner_.get(),
    604                                        file_task_runner_.get());
    605   file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    606 
    607   sync_context_ = new LocalFileSyncContext(
    608       dir_.path(), in_memory_env_.get(),
    609       ui_task_runner_.get(), io_task_runner_.get());
    610   ASSERT_EQ(SYNC_STATUS_OK,
    611             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    612   ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    613 
    614   // Record the initial usage (likely 0).
    615   int64 initial_usage = -1;
    616   int64 quota = -1;
    617   EXPECT_EQ(quota::kQuotaStatusOk,
    618             file_system.GetUsageAndQuota(&initial_usage, &quota));
    619 
    620   // Create a file and directory in the file_system.
    621   const FileSystemURL kFile(file_system.URL("file"));
    622   const FileSystemURL kDir(file_system.URL("dir"));
    623   const FileSystemURL kChild(file_system.URL("dir/child"));
    624 
    625   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
    626   EXPECT_EQ(base::File::FILE_OK, file_system.CreateDirectory(kDir));
    627   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kChild));
    628 
    629   // file_system's change tracker must have recorded the creation.
    630   FileSystemURLSet urls;
    631   file_system.GetChangedURLsInTracker(&urls);
    632   ASSERT_EQ(3U, urls.size());
    633   ASSERT_TRUE(ContainsKey(urls, kFile));
    634   ASSERT_TRUE(ContainsKey(urls, kDir));
    635   ASSERT_TRUE(ContainsKey(urls, kChild));
    636   for (FileSystemURLSet::iterator iter = urls.begin();
    637        iter != urls.end(); ++iter) {
    638     file_system.ClearChangeForURLInTracker(*iter);
    639   }
    640 
    641   // At this point the usage must be greater than the initial usage.
    642   int64 new_usage = -1;
    643   EXPECT_EQ(quota::kQuotaStatusOk,
    644             file_system.GetUsageAndQuota(&new_usage, &quota));
    645   EXPECT_GT(new_usage, initial_usage);
    646 
    647   // Now let's apply remote deletion changes.
    648   FileChange change(FileChange::FILE_CHANGE_DELETE,
    649                     SYNC_FILE_TYPE_FILE);
    650   EXPECT_EQ(SYNC_STATUS_OK,
    651             ApplyRemoteChange(file_system.file_system_context(),
    652                               change, base::FilePath(), kFile,
    653                               SYNC_FILE_TYPE_FILE));
    654 
    655   // The implementation doesn't check file type for deletion, and it must be ok
    656   // even if we don't know if the deletion change was for a file or a directory.
    657   change = FileChange(FileChange::FILE_CHANGE_DELETE,
    658                       SYNC_FILE_TYPE_UNKNOWN);
    659   EXPECT_EQ(SYNC_STATUS_OK,
    660             ApplyRemoteChange(file_system.file_system_context(),
    661                               change, base::FilePath(), kDir,
    662                               SYNC_FILE_TYPE_DIRECTORY));
    663 
    664   // Check the directory/files are deleted successfully.
    665   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    666             file_system.FileExists(kFile));
    667   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    668             file_system.DirectoryExists(kDir));
    669   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    670             file_system.FileExists(kChild));
    671 
    672   // The changes applied by ApplyRemoteChange should not be recorded in
    673   // the change tracker.
    674   urls.clear();
    675   file_system.GetChangedURLsInTracker(&urls);
    676   EXPECT_TRUE(urls.empty());
    677 
    678   // The quota usage data must have reflected the deletion.
    679   EXPECT_EQ(quota::kQuotaStatusOk,
    680             file_system.GetUsageAndQuota(&new_usage, &quota));
    681   EXPECT_EQ(new_usage, initial_usage);
    682 
    683   sync_context_->ShutdownOnUIThread();
    684   sync_context_ = NULL;
    685   file_system.TearDown();
    686 }
    687 
    688 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion_ForRoot) {
    689   CannedSyncableFileSystem file_system(GURL(kOrigin1),
    690                                        in_memory_env_.get(),
    691                                        io_task_runner_.get(),
    692                                        file_task_runner_.get());
    693   file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    694 
    695   sync_context_ = new LocalFileSyncContext(
    696       dir_.path(), in_memory_env_.get(),
    697       ui_task_runner_.get(), io_task_runner_.get());
    698   ASSERT_EQ(SYNC_STATUS_OK,
    699             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    700   ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    701 
    702   // Record the initial usage (likely 0).
    703   int64 initial_usage = -1;
    704   int64 quota = -1;
    705   EXPECT_EQ(quota::kQuotaStatusOk,
    706             file_system.GetUsageAndQuota(&initial_usage, &quota));
    707 
    708   // Create a file and directory in the file_system.
    709   const FileSystemURL kFile(file_system.URL("file"));
    710   const FileSystemURL kDir(file_system.URL("dir"));
    711   const FileSystemURL kChild(file_system.URL("dir/child"));
    712 
    713   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
    714   EXPECT_EQ(base::File::FILE_OK, file_system.CreateDirectory(kDir));
    715   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kChild));
    716 
    717   // At this point the usage must be greater than the initial usage.
    718   int64 new_usage = -1;
    719   EXPECT_EQ(quota::kQuotaStatusOk,
    720             file_system.GetUsageAndQuota(&new_usage, &quota));
    721   EXPECT_GT(new_usage, initial_usage);
    722 
    723   const FileSystemURL kRoot(file_system.URL(""));
    724 
    725   // Now let's apply remote deletion changes for the root.
    726   FileChange change(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_DIRECTORY);
    727   EXPECT_EQ(SYNC_STATUS_OK,
    728             ApplyRemoteChange(file_system.file_system_context(),
    729                               change, base::FilePath(), kRoot,
    730                               SYNC_FILE_TYPE_DIRECTORY));
    731 
    732   // Check the directory/files are deleted successfully.
    733   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    734             file_system.FileExists(kFile));
    735   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    736             file_system.DirectoryExists(kDir));
    737   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    738             file_system.FileExists(kChild));
    739 
    740   // All changes made for the previous creation must have been also reset.
    741   FileSystemURLSet urls;
    742   file_system.GetChangedURLsInTracker(&urls);
    743   EXPECT_TRUE(urls.empty());
    744 
    745   // The quota usage data must have reflected the deletion.
    746   EXPECT_EQ(quota::kQuotaStatusOk,
    747             file_system.GetUsageAndQuota(&new_usage, &quota));
    748   EXPECT_EQ(new_usage, initial_usage);
    749 
    750   sync_context_->ShutdownOnUIThread();
    751   sync_context_ = NULL;
    752   file_system.TearDown();
    753 }
    754 
    755 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate) {
    756   base::ScopedTempDir temp_dir;
    757   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    758 
    759   CannedSyncableFileSystem file_system(GURL(kOrigin1),
    760                                        in_memory_env_.get(),
    761                                        io_task_runner_.get(),
    762                                        file_task_runner_.get());
    763   file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    764 
    765   sync_context_ = new LocalFileSyncContext(
    766       dir_.path(), in_memory_env_.get(),
    767       ui_task_runner_.get(), io_task_runner_.get());
    768   ASSERT_EQ(SYNC_STATUS_OK,
    769             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    770   ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    771 
    772   const FileSystemURL kFile1(file_system.URL("file1"));
    773   const FileSystemURL kFile2(file_system.URL("file2"));
    774   const FileSystemURL kDir(file_system.URL("dir"));
    775 
    776   const char kTestFileData0[] = "0123456789";
    777   const char kTestFileData1[] = "Lorem ipsum!";
    778   const char kTestFileData2[] = "This is sample test data.";
    779 
    780   // Create kFile1 and populate it with kTestFileData0.
    781   EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile1));
    782   EXPECT_EQ(static_cast<int64>(arraysize(kTestFileData0) - 1),
    783             file_system.WriteString(kFile1, kTestFileData0));
    784 
    785   // kFile2 and kDir are not there yet.
    786   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    787             file_system.FileExists(kFile2));
    788   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
    789             file_system.DirectoryExists(kDir));
    790 
    791   // file_system's change tracker must have recorded the creation.
    792   FileSystemURLSet urls;
    793   file_system.GetChangedURLsInTracker(&urls);
    794   ASSERT_EQ(1U, urls.size());
    795   EXPECT_TRUE(ContainsKey(urls, kFile1));
    796   file_system.ClearChangeForURLInTracker(*urls.begin());
    797 
    798   // Prepare temporary files which represent the remote file data.
    799   const base::FilePath kFilePath1(temp_dir.path().Append(FPL("file1")));
    800   const base::FilePath kFilePath2(temp_dir.path().Append(FPL("file2")));
    801 
    802   ASSERT_EQ(static_cast<int>(arraysize(kTestFileData1) - 1),
    803             base::WriteFile(kFilePath1, kTestFileData1,
    804                             arraysize(kTestFileData1) - 1));
    805   ASSERT_EQ(static_cast<int>(arraysize(kTestFileData2) - 1),
    806             base::WriteFile(kFilePath2, kTestFileData2,
    807                             arraysize(kTestFileData2) - 1));
    808 
    809   // Record the usage.
    810   int64 usage = -1, new_usage = -1;
    811   int64 quota = -1;
    812   EXPECT_EQ(quota::kQuotaStatusOk,
    813             file_system.GetUsageAndQuota(&usage, &quota));
    814 
    815   // Here in the local filesystem we have:
    816   //  * kFile1 with kTestFileData0
    817   //
    818   // In the remote side let's assume we have:
    819   //  * kFile1 with kTestFileData1
    820   //  * kFile2 with kTestFileData2
    821   //  * kDir
    822   //
    823   // By calling ApplyChange's:
    824   //  * kFile1 will be updated to have kTestFileData1
    825   //  * kFile2 will be created
    826   //  * kDir will be created
    827 
    828   // Apply the remote change to kFile1 (which will update the file).
    829   FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    830                     SYNC_FILE_TYPE_FILE);
    831   EXPECT_EQ(SYNC_STATUS_OK,
    832             ApplyRemoteChange(file_system.file_system_context(),
    833                               change, kFilePath1, kFile1,
    834                               SYNC_FILE_TYPE_FILE));
    835 
    836   // Check if the usage has been increased by (kTestFileData1 - kTestFileData0).
    837   const int updated_size =
    838       arraysize(kTestFileData1) - arraysize(kTestFileData0);
    839   EXPECT_EQ(quota::kQuotaStatusOk,
    840             file_system.GetUsageAndQuota(&new_usage, &quota));
    841   EXPECT_EQ(updated_size, new_usage - usage);
    842 
    843   // Apply remote changes to kFile2 and kDir (should create a file and
    844   // directory respectively).
    845   // They are non-existent yet so their expected file type (the last
    846   // parameter of ApplyRemoteChange) are
    847   // SYNC_FILE_TYPE_UNKNOWN.
    848   change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    849                       SYNC_FILE_TYPE_FILE);
    850   EXPECT_EQ(SYNC_STATUS_OK,
    851             ApplyRemoteChange(file_system.file_system_context(),
    852                               change, kFilePath2, kFile2,
    853                               SYNC_FILE_TYPE_UNKNOWN));
    854 
    855   change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    856                       SYNC_FILE_TYPE_DIRECTORY);
    857   EXPECT_EQ(SYNC_STATUS_OK,
    858             ApplyRemoteChange(file_system.file_system_context(),
    859                               change, base::FilePath(), kDir,
    860                               SYNC_FILE_TYPE_UNKNOWN));
    861 
    862   // Calling ApplyRemoteChange with different file type should be handled as
    863   // overwrite.
    864   change =
    865       FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE);
    866   EXPECT_EQ(SYNC_STATUS_OK,
    867             ApplyRemoteChange(file_system.file_system_context(),
    868                               change,
    869                               kFilePath1,
    870                               kDir,
    871                               SYNC_FILE_TYPE_DIRECTORY));
    872   EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kDir));
    873 
    874   change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    875                       SYNC_FILE_TYPE_DIRECTORY);
    876   EXPECT_EQ(SYNC_STATUS_OK,
    877             ApplyRemoteChange(file_system.file_system_context(),
    878                               change,
    879                               kFilePath1,
    880                               kDir,
    881                               SYNC_FILE_TYPE_FILE));
    882 
    883   // Creating a file/directory must have increased the usage more than
    884   // the size of kTestFileData2.
    885   new_usage = usage;
    886   EXPECT_EQ(quota::kQuotaStatusOk,
    887             file_system.GetUsageAndQuota(&new_usage, &quota));
    888   EXPECT_GT(new_usage,
    889             static_cast<int64>(usage + arraysize(kTestFileData2) - 1));
    890 
    891   // The changes applied by ApplyRemoteChange should not be recorded in
    892   // the change tracker.
    893   urls.clear();
    894   file_system.GetChangedURLsInTracker(&urls);
    895   EXPECT_TRUE(urls.empty());
    896 
    897   // Make sure all three files/directory exist.
    898   EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kFile1));
    899   EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kFile2));
    900   EXPECT_EQ(base::File::FILE_OK, file_system.DirectoryExists(kDir));
    901 
    902   sync_context_->ShutdownOnUIThread();
    903   file_system.TearDown();
    904 }
    905 
    906 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate_NoParent) {
    907   base::ScopedTempDir temp_dir;
    908   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    909 
    910   CannedSyncableFileSystem file_system(GURL(kOrigin1),
    911                                        in_memory_env_.get(),
    912                                        io_task_runner_.get(),
    913                                        file_task_runner_.get());
    914   file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
    915 
    916   sync_context_ = new LocalFileSyncContext(
    917       dir_.path(), in_memory_env_.get(),
    918       ui_task_runner_.get(), io_task_runner_.get());
    919   ASSERT_EQ(SYNC_STATUS_OK,
    920             file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
    921   ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
    922 
    923   const char kTestFileData[] = "Lorem ipsum!";
    924   const FileSystemURL kDir(file_system.URL("dir"));
    925   const FileSystemURL kFile(file_system.URL("dir/file"));
    926 
    927   // Either kDir or kFile not exist yet.
    928   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file_system.FileExists(kDir));
    929   EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file_system.FileExists(kFile));
    930 
    931   // Prepare a temporary file which represents remote file data.
    932   const base::FilePath kFilePath(temp_dir.path().Append(FPL("file")));
    933   ASSERT_EQ(static_cast<int>(arraysize(kTestFileData) - 1),
    934             base::WriteFile(kFilePath, kTestFileData,
    935                             arraysize(kTestFileData) - 1));
    936 
    937   // Calling ApplyChange's with kFilePath should create
    938   // kFile along with kDir.
    939   FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
    940                     SYNC_FILE_TYPE_FILE);
    941   EXPECT_EQ(SYNC_STATUS_OK,
    942             ApplyRemoteChange(file_system.file_system_context(),
    943                               change, kFilePath, kFile,
    944                               SYNC_FILE_TYPE_UNKNOWN));
    945 
    946   // The changes applied by ApplyRemoteChange should not be recorded in
    947   // the change tracker.
    948   FileSystemURLSet urls;
    949   urls.clear();
    950   file_system.GetChangedURLsInTracker(&urls);
    951   EXPECT_TRUE(urls.empty());
    952 
    953   // Make sure kDir and kFile are created by ApplyRemoteChange.
    954   EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kFile));
    955   EXPECT_EQ(base::File::FILE_OK, file_system.DirectoryExists(kDir));
    956 
    957   sync_context_->ShutdownOnUIThread();
    958   file_system.TearDown();
    959 }
    960 
    961 }  // namespace sync_file_system
    962