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