Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / local / local_file_sync_context_unittest.cc
blob9e2ebeae5f349144a6de6a6c147424bfb2294c24
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.
5 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
7 #include <vector>
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/platform_file.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
17 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
18 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
19 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
20 #include "chrome/browser/sync_file_system/sync_status_code.h"
21 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/test/test_browser_thread_bundle.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "webkit/browser/blob/mock_blob_url_request_context.h"
26 #include "webkit/browser/fileapi/file_system_context.h"
27 #include "webkit/browser/fileapi/file_system_operation_runner.h"
28 #include "webkit/browser/fileapi/isolated_context.h"
29 #include "webkit/common/blob/scoped_file.h"
31 #define FPL FILE_PATH_LITERAL
33 using content::BrowserThread;
34 using fileapi::FileSystemContext;
35 using fileapi::FileSystemURL;
36 using fileapi::FileSystemURLSet;
38 // This tests LocalFileSyncContext behavior in multi-thread /
39 // multi-file-system-context environment.
40 // Basic combined tests (single-thread / single-file-system-context)
41 // that involve LocalFileSyncContext are also in
42 // syncable_file_system_unittests.cc.
44 namespace sync_file_system {
46 namespace {
47 const char kOrigin1[] = "http://example.com";
48 const char kOrigin2[] = "http://chromium.org";
51 class LocalFileSyncContextTest : public testing::Test {
52 protected:
53 LocalFileSyncContextTest()
54 : thread_bundle_(
55 content::TestBrowserThreadBundle::REAL_FILE_THREAD |
56 content::TestBrowserThreadBundle::REAL_IO_THREAD),
57 status_(SYNC_FILE_ERROR_FAILED),
58 file_error_(base::PLATFORM_FILE_ERROR_FAILED),
59 async_modify_finished_(false),
60 has_inflight_prepare_for_sync_(false) {}
62 virtual void SetUp() OVERRIDE {
63 RegisterSyncableFileSystem();
64 ASSERT_TRUE(dir_.CreateUniqueTempDir());
66 ui_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
67 io_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
68 BrowserThread::IO);
69 file_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
70 BrowserThread::IO);
73 virtual void TearDown() OVERRIDE {
74 RevokeSyncableFileSystem();
77 void StartPrepareForSync(FileSystemContext* file_system_context,
78 const FileSystemURL& url,
79 LocalFileSyncContext::SyncMode sync_mode,
80 SyncFileMetadata* metadata,
81 FileChangeList* changes,
82 webkit_blob::ScopedFile* snapshot) {
83 ASSERT_TRUE(changes != NULL);
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));
95 SyncStatusCode PrepareForSync(FileSystemContext* file_system_context,
96 const FileSystemURL& url,
97 LocalFileSyncContext::SyncMode sync_mode,
98 SyncFileMetadata* metadata,
99 FileChangeList* changes,
100 webkit_blob::ScopedFile* snapshot) {
101 StartPrepareForSync(file_system_context, url, sync_mode,
102 metadata, changes, snapshot);
103 base::MessageLoop::current()->Run();
104 return status_;
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 webkit_blob::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);
120 void DidPrepareForSync(SyncFileMetadata* metadata_out,
121 FileChangeList* changes_out,
122 webkit_blob::ScopedFile* snapshot_out,
123 SyncStatusCode status,
124 const LocalFileSyncInfo& sync_file_info,
125 webkit_blob::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();
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());
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, NULL));
151 EXPECT_EQ(expected_file_type, metadata.file_type);
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_;
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());
173 void StartModifyFileOnIOThread(CannedSyncableFileSystem* file_system,
174 const FileSystemURL& url) {
175 ASSERT_TRUE(file_system != NULL);
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;
185 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
186 file_error_ = base::PLATFORM_FILE_ERROR_FAILED;
187 file_system->operation_runner()->Truncate(
188 url, 1, base::Bind(&LocalFileSyncContextTest::DidModifyFile,
189 base::Unretained(this)));
192 base::PlatformFileError WaitUntilModifyFileIsDone() {
193 while (!async_modify_finished_)
194 base::MessageLoop::current()->RunUntilIdle();
195 return file_error_;
198 void DidModifyFile(base::PlatformFileError 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;
207 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
208 file_error_ = error;
209 async_modify_finished_ = true;
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));
228 void PrepareForSync_Basic(LocalFileSyncContext::SyncMode sync_mode,
229 SyncStatusCode simulate_sync_finish_status) {
230 CannedSyncableFileSystem file_system(GURL(kOrigin1),
231 io_task_runner_.get(),
232 file_task_runner_.get());
233 file_system.SetUp();
234 sync_context_ = new LocalFileSyncContext(
235 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
236 ASSERT_EQ(SYNC_STATUS_OK,
237 file_system.MaybeInitializeFileSystemContext(
238 sync_context_.get()));
239 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
241 const FileSystemURL kFile(file_system.URL("file"));
242 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile));
244 SyncFileMetadata metadata;
245 FileChangeList changes;
246 EXPECT_EQ(SYNC_STATUS_OK,
247 PrepareForSync(file_system.file_system_context(), kFile,
248 sync_mode, &metadata, &changes, NULL));
249 EXPECT_EQ(1U, changes.size());
250 EXPECT_TRUE(changes.list().back().IsFile());
251 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
253 // We should see the same set of changes.
254 file_system.GetChangesForURLInTracker(kFile, &changes);
255 EXPECT_EQ(1U, changes.size());
256 EXPECT_TRUE(changes.list().back().IsFile());
257 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
259 SimulateFinishSync(file_system.file_system_context(), kFile,
260 simulate_sync_finish_status, sync_mode);
262 file_system.GetChangesForURLInTracker(kFile, &changes);
263 if (simulate_sync_finish_status == SYNC_STATUS_OK) {
264 // The change's cleared.
265 EXPECT_TRUE(changes.empty());
266 } else {
267 EXPECT_EQ(1U, changes.size());
268 EXPECT_TRUE(changes.list().back().IsFile());
269 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
272 sync_context_->ShutdownOnUIThread();
273 sync_context_ = NULL;
275 file_system.TearDown();
278 void PrepareForSync_WriteDuringSync(
279 LocalFileSyncContext::SyncMode sync_mode) {
280 CannedSyncableFileSystem file_system(GURL(kOrigin1),
281 io_task_runner_.get(),
282 file_task_runner_.get());
283 file_system.SetUp();
284 sync_context_ = new LocalFileSyncContext(
285 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
286 ASSERT_EQ(SYNC_STATUS_OK,
287 file_system.MaybeInitializeFileSystemContext(
288 sync_context_.get()));
289 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
291 const FileSystemURL kFile(file_system.URL("file"));
292 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile));
294 SyncFileMetadata metadata;
295 FileChangeList changes;
296 webkit_blob::ScopedFile snapshot;
297 EXPECT_EQ(SYNC_STATUS_OK,
298 PrepareForSync(file_system.file_system_context(), kFile,
299 sync_mode, &metadata, &changes, &snapshot));
300 EXPECT_EQ(1U, changes.size());
301 EXPECT_TRUE(changes.list().back().IsFile());
302 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
304 EXPECT_EQ(sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT,
305 !snapshot.path().empty());
307 // Tracker keeps same set of changes.
308 file_system.GetChangesForURLInTracker(kFile, &changes);
309 EXPECT_EQ(1U, changes.size());
310 EXPECT_TRUE(changes.list().back().IsFile());
311 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
313 StartModifyFileOnIOThread(&file_system, kFile);
315 if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) {
316 // Write should succeed.
317 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone());
318 } else {
319 base::MessageLoop::current()->RunUntilIdle();
320 EXPECT_FALSE(async_modify_finished_);
323 SimulateFinishSync(file_system.file_system_context(), kFile,
324 SYNC_STATUS_OK, sync_mode);
326 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone());
328 // Sync succeeded, but the other change that was made during or
329 // after sync is recorded.
330 file_system.GetChangesForURLInTracker(kFile, &changes);
331 EXPECT_EQ(1U, changes.size());
332 EXPECT_TRUE(changes.list().back().IsFile());
333 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
335 sync_context_->ShutdownOnUIThread();
336 sync_context_ = NULL;
338 file_system.TearDown();
341 ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
343 base::ScopedTempDir dir_;
345 // These need to remain until the very end.
346 content::TestBrowserThreadBundle thread_bundle_;
348 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
349 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
350 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
352 scoped_refptr<LocalFileSyncContext> sync_context_;
354 SyncStatusCode status_;
355 base::PlatformFileError file_error_;
356 bool async_modify_finished_;
357 bool has_inflight_prepare_for_sync_;
360 TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) {
361 sync_context_ =
362 new LocalFileSyncContext(
363 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
364 sync_context_->ShutdownOnUIThread();
367 TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) {
368 CannedSyncableFileSystem file_system(GURL(kOrigin1),
369 io_task_runner_.get(),
370 file_task_runner_.get());
371 file_system.SetUp();
373 sync_context_ = new LocalFileSyncContext(
374 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
376 // Initializes file_system using |sync_context_|.
377 EXPECT_EQ(SYNC_STATUS_OK,
378 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
380 // Make sure everything's set up for file_system to be able to handle
381 // syncable file system operations.
382 EXPECT_TRUE(file_system.backend()->sync_context() != NULL);
383 EXPECT_TRUE(file_system.backend()->change_tracker() != NULL);
384 EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context());
386 // Calling MaybeInitialize for the same context multiple times must be ok.
387 EXPECT_EQ(SYNC_STATUS_OK,
388 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
389 EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context());
391 // Opens the file_system, perform some operation and see if the change tracker
392 // correctly captures the change.
393 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
395 const FileSystemURL kURL(file_system.URL("foo"));
396 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kURL));
398 FileSystemURLSet urls;
399 file_system.GetChangedURLsInTracker(&urls);
400 ASSERT_EQ(1U, urls.size());
401 EXPECT_TRUE(ContainsKey(urls, kURL));
403 // Finishing the test.
404 sync_context_->ShutdownOnUIThread();
405 file_system.TearDown();
408 TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) {
409 CannedSyncableFileSystem file_system1(GURL(kOrigin1),
410 io_task_runner_.get(),
411 file_task_runner_.get());
412 CannedSyncableFileSystem file_system2(GURL(kOrigin2),
413 io_task_runner_.get(),
414 file_task_runner_.get());
415 file_system1.SetUp();
416 file_system2.SetUp();
418 sync_context_ = new LocalFileSyncContext(
419 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
421 // Initializes file_system1 and file_system2.
422 EXPECT_EQ(SYNC_STATUS_OK,
423 file_system1.MaybeInitializeFileSystemContext(sync_context_.get()));
424 EXPECT_EQ(SYNC_STATUS_OK,
425 file_system2.MaybeInitializeFileSystemContext(sync_context_.get()));
427 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system1.OpenFileSystem());
428 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system2.OpenFileSystem());
430 const FileSystemURL kURL1(file_system1.URL("foo"));
431 const FileSystemURL kURL2(file_system2.URL("bar"));
433 // Creates a file in file_system1.
434 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system1.CreateFile(kURL1));
436 // file_system1's tracker must have recorded the change.
437 FileSystemURLSet urls;
438 file_system1.GetChangedURLsInTracker(&urls);
439 ASSERT_EQ(1U, urls.size());
440 EXPECT_TRUE(ContainsKey(urls, kURL1));
442 // file_system1's tracker must have no change.
443 urls.clear();
444 file_system2.GetChangedURLsInTracker(&urls);
445 ASSERT_TRUE(urls.empty());
447 // Creates a directory in file_system2.
448 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system2.CreateDirectory(kURL2));
450 // file_system1's tracker must have the change for kURL1 as before.
451 urls.clear();
452 file_system1.GetChangedURLsInTracker(&urls);
453 ASSERT_EQ(1U, urls.size());
454 EXPECT_TRUE(ContainsKey(urls, kURL1));
456 // file_system2's tracker now must have the change for kURL2.
457 urls.clear();
458 file_system2.GetChangedURLsInTracker(&urls);
459 ASSERT_EQ(1U, urls.size());
460 EXPECT_TRUE(ContainsKey(urls, kURL2));
462 SyncFileMetadata metadata;
463 FileChangeList changes;
464 EXPECT_EQ(SYNC_STATUS_OK,
465 PrepareForSync(file_system1.file_system_context(), kURL1,
466 LocalFileSyncContext::SYNC_EXCLUSIVE,
467 &metadata, &changes, NULL));
468 EXPECT_EQ(1U, changes.size());
469 EXPECT_TRUE(changes.list().back().IsFile());
470 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
471 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
472 EXPECT_EQ(0, metadata.size);
474 changes.clear();
475 EXPECT_EQ(SYNC_STATUS_OK,
476 PrepareForSync(file_system2.file_system_context(), kURL2,
477 LocalFileSyncContext::SYNC_EXCLUSIVE,
478 &metadata, &changes, NULL));
479 EXPECT_EQ(1U, changes.size());
480 EXPECT_FALSE(changes.list().back().IsFile());
481 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
482 EXPECT_EQ(SYNC_FILE_TYPE_DIRECTORY, metadata.file_type);
483 EXPECT_EQ(0, metadata.size);
485 sync_context_->ShutdownOnUIThread();
486 sync_context_ = NULL;
488 file_system1.TearDown();
489 file_system2.TearDown();
492 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Exclusive) {
493 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
494 SYNC_STATUS_OK);
497 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Snapshot) {
498 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
499 SYNC_STATUS_OK);
502 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Exclusive) {
503 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
504 SYNC_STATUS_FAILED);
507 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Snapshot) {
508 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
509 SYNC_STATUS_FAILED);
512 TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Exclusive) {
513 PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_EXCLUSIVE);
516 TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Snapshot) {
517 PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_SNAPSHOT);
520 // LocalFileSyncContextTest.PrepareSyncWhileWriting is flaky on android.
521 // http://crbug.com/239793
522 // It is also flaky on the TSAN v2 bots, and hangs other bots.
523 // http://crbug.com/305905.
524 TEST_F(LocalFileSyncContextTest, DISABLED_PrepareSyncWhileWriting) {
525 CannedSyncableFileSystem file_system(GURL(kOrigin1),
526 io_task_runner_.get(),
527 file_task_runner_.get());
528 file_system.SetUp();
529 sync_context_ = new LocalFileSyncContext(
530 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
531 EXPECT_EQ(SYNC_STATUS_OK,
532 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
534 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
536 const FileSystemURL kURL1(file_system.URL("foo"));
538 // Creates a file in file_system.
539 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kURL1));
541 // Kick file write on IO thread.
542 StartModifyFileOnIOThread(&file_system, kURL1);
544 // Until the operation finishes PrepareForSync should return BUSY error.
545 SyncFileMetadata metadata;
546 metadata.file_type = SYNC_FILE_TYPE_UNKNOWN;
547 FileChangeList changes;
548 EXPECT_EQ(SYNC_STATUS_FILE_BUSY,
549 PrepareForSync(file_system.file_system_context(), kURL1,
550 LocalFileSyncContext::SYNC_EXCLUSIVE,
551 &metadata, &changes, NULL));
552 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
554 // Register PrepareForSync method to be invoked when kURL1 becomes
555 // syncable. (Actually this may be done after all operations are done
556 // on IO thread in this test.)
557 metadata.file_type = SYNC_FILE_TYPE_UNKNOWN;
558 changes.clear();
559 sync_context_->RegisterURLForWaitingSync(
560 kURL1, GetPrepareForSyncClosure(file_system.file_system_context(), kURL1,
561 LocalFileSyncContext::SYNC_EXCLUSIVE,
562 &metadata, &changes, NULL));
564 // Wait for the completion.
565 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone());
567 // The PrepareForSync must have been started; wait until DidPrepareForSync
568 // is done.
569 base::MessageLoop::current()->Run();
570 ASSERT_FALSE(has_inflight_prepare_for_sync_);
572 // Now PrepareForSync should have run and returned OK.
573 EXPECT_EQ(SYNC_STATUS_OK, status_);
574 EXPECT_EQ(1U, changes.size());
575 EXPECT_TRUE(changes.list().back().IsFile());
576 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
577 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
578 EXPECT_EQ(1, metadata.size);
580 sync_context_->ShutdownOnUIThread();
581 sync_context_ = NULL;
582 file_system.TearDown();
585 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion) {
586 CannedSyncableFileSystem file_system(GURL(kOrigin1),
587 io_task_runner_.get(),
588 file_task_runner_.get());
589 file_system.SetUp();
591 sync_context_ = new LocalFileSyncContext(
592 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
593 ASSERT_EQ(SYNC_STATUS_OK,
594 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
595 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
597 // Record the initial usage (likely 0).
598 int64 initial_usage = -1;
599 int64 quota = -1;
600 EXPECT_EQ(quota::kQuotaStatusOk,
601 file_system.GetUsageAndQuota(&initial_usage, &quota));
603 // Create a file and directory in the file_system.
604 const FileSystemURL kFile(file_system.URL("file"));
605 const FileSystemURL kDir(file_system.URL("dir"));
606 const FileSystemURL kChild(file_system.URL("dir/child"));
608 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile));
609 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateDirectory(kDir));
610 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kChild));
612 // file_system's change tracker must have recorded the creation.
613 FileSystemURLSet urls;
614 file_system.GetChangedURLsInTracker(&urls);
615 ASSERT_EQ(3U, urls.size());
616 ASSERT_TRUE(ContainsKey(urls, kFile));
617 ASSERT_TRUE(ContainsKey(urls, kDir));
618 ASSERT_TRUE(ContainsKey(urls, kChild));
619 for (FileSystemURLSet::iterator iter = urls.begin();
620 iter != urls.end(); ++iter) {
621 file_system.ClearChangeForURLInTracker(*iter);
624 // At this point the usage must be greater than the initial usage.
625 int64 new_usage = -1;
626 EXPECT_EQ(quota::kQuotaStatusOk,
627 file_system.GetUsageAndQuota(&new_usage, &quota));
628 EXPECT_GT(new_usage, initial_usage);
630 // Now let's apply remote deletion changes.
631 FileChange change(FileChange::FILE_CHANGE_DELETE,
632 SYNC_FILE_TYPE_FILE);
633 EXPECT_EQ(SYNC_STATUS_OK,
634 ApplyRemoteChange(file_system.file_system_context(),
635 change, base::FilePath(), kFile,
636 SYNC_FILE_TYPE_FILE));
638 // The implementation doesn't check file type for deletion, and it must be ok
639 // even if we don't know if the deletion change was for a file or a directory.
640 change = FileChange(FileChange::FILE_CHANGE_DELETE,
641 SYNC_FILE_TYPE_UNKNOWN);
642 EXPECT_EQ(SYNC_STATUS_OK,
643 ApplyRemoteChange(file_system.file_system_context(),
644 change, base::FilePath(), kDir,
645 SYNC_FILE_TYPE_DIRECTORY));
647 // Check the directory/files are deleted successfully.
648 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
649 file_system.FileExists(kFile));
650 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
651 file_system.DirectoryExists(kDir));
652 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
653 file_system.FileExists(kChild));
655 // The changes applied by ApplyRemoteChange should not be recorded in
656 // the change tracker.
657 urls.clear();
658 file_system.GetChangedURLsInTracker(&urls);
659 EXPECT_TRUE(urls.empty());
661 // The quota usage data must have reflected the deletion.
662 EXPECT_EQ(quota::kQuotaStatusOk,
663 file_system.GetUsageAndQuota(&new_usage, &quota));
664 EXPECT_EQ(new_usage, initial_usage);
666 sync_context_->ShutdownOnUIThread();
667 sync_context_ = NULL;
668 file_system.TearDown();
671 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion_ForRoot) {
672 CannedSyncableFileSystem file_system(GURL(kOrigin1),
673 io_task_runner_.get(),
674 file_task_runner_.get());
675 file_system.SetUp();
677 sync_context_ = new LocalFileSyncContext(
678 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
679 ASSERT_EQ(SYNC_STATUS_OK,
680 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
681 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
683 // Record the initial usage (likely 0).
684 int64 initial_usage = -1;
685 int64 quota = -1;
686 EXPECT_EQ(quota::kQuotaStatusOk,
687 file_system.GetUsageAndQuota(&initial_usage, &quota));
689 // Create a file and directory in the file_system.
690 const FileSystemURL kFile(file_system.URL("file"));
691 const FileSystemURL kDir(file_system.URL("dir"));
692 const FileSystemURL kChild(file_system.URL("dir/child"));
694 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile));
695 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateDirectory(kDir));
696 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kChild));
698 // At this point the usage must be greater than the initial usage.
699 int64 new_usage = -1;
700 EXPECT_EQ(quota::kQuotaStatusOk,
701 file_system.GetUsageAndQuota(&new_usage, &quota));
702 EXPECT_GT(new_usage, initial_usage);
704 const FileSystemURL kRoot(file_system.URL(""));
706 // Now let's apply remote deletion changes for the root.
707 FileChange change(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_DIRECTORY);
708 EXPECT_EQ(SYNC_STATUS_OK,
709 ApplyRemoteChange(file_system.file_system_context(),
710 change, base::FilePath(), kRoot,
711 SYNC_FILE_TYPE_DIRECTORY));
713 // Check the directory/files are deleted successfully.
714 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
715 file_system.FileExists(kFile));
716 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
717 file_system.DirectoryExists(kDir));
718 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
719 file_system.FileExists(kChild));
721 // All changes made for the previous creation must have been also reset.
722 FileSystemURLSet urls;
723 file_system.GetChangedURLsInTracker(&urls);
724 EXPECT_TRUE(urls.empty());
726 // The quota usage data must have reflected the deletion.
727 EXPECT_EQ(quota::kQuotaStatusOk,
728 file_system.GetUsageAndQuota(&new_usage, &quota));
729 EXPECT_EQ(new_usage, initial_usage);
731 sync_context_->ShutdownOnUIThread();
732 sync_context_ = NULL;
733 file_system.TearDown();
736 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate) {
737 base::ScopedTempDir temp_dir;
738 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
740 CannedSyncableFileSystem file_system(GURL(kOrigin1),
741 io_task_runner_.get(),
742 file_task_runner_.get());
743 file_system.SetUp();
745 sync_context_ = new LocalFileSyncContext(
746 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
747 ASSERT_EQ(SYNC_STATUS_OK,
748 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
749 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
751 const FileSystemURL kFile1(file_system.URL("file1"));
752 const FileSystemURL kFile2(file_system.URL("file2"));
753 const FileSystemURL kDir(file_system.URL("dir"));
755 const char kTestFileData0[] = "0123456789";
756 const char kTestFileData1[] = "Lorem ipsum!";
757 const char kTestFileData2[] = "This is sample test data.";
759 // Create kFile1 and populate it with kTestFileData0.
760 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile1));
761 EXPECT_EQ(static_cast<int64>(arraysize(kTestFileData0) - 1),
762 file_system.WriteString(kFile1, kTestFileData0));
764 // kFile2 and kDir are not there yet.
765 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
766 file_system.FileExists(kFile2));
767 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND,
768 file_system.DirectoryExists(kDir));
770 // file_system's change tracker must have recorded the creation.
771 FileSystemURLSet urls;
772 file_system.GetChangedURLsInTracker(&urls);
773 ASSERT_EQ(1U, urls.size());
774 EXPECT_TRUE(ContainsKey(urls, kFile1));
775 file_system.ClearChangeForURLInTracker(*urls.begin());
777 // Prepare temporary files which represent the remote file data.
778 const base::FilePath kFilePath1(temp_dir.path().Append(FPL("file1")));
779 const base::FilePath kFilePath2(temp_dir.path().Append(FPL("file2")));
781 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData1) - 1),
782 file_util::WriteFile(kFilePath1, kTestFileData1,
783 arraysize(kTestFileData1) - 1));
784 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData2) - 1),
785 file_util::WriteFile(kFilePath2, kTestFileData2,
786 arraysize(kTestFileData2) - 1));
788 // Record the usage.
789 int64 usage = -1, new_usage = -1;
790 int64 quota = -1;
791 EXPECT_EQ(quota::kQuotaStatusOk,
792 file_system.GetUsageAndQuota(&usage, &quota));
794 // Here in the local filesystem we have:
795 // * kFile1 with kTestFileData0
797 // In the remote side let's assume we have:
798 // * kFile1 with kTestFileData1
799 // * kFile2 with kTestFileData2
800 // * kDir
802 // By calling ApplyChange's:
803 // * kFile1 will be updated to have kTestFileData1
804 // * kFile2 will be created
805 // * kDir will be created
807 // Apply the remote change to kFile1 (which will update the file).
808 FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
809 SYNC_FILE_TYPE_FILE);
810 EXPECT_EQ(SYNC_STATUS_OK,
811 ApplyRemoteChange(file_system.file_system_context(),
812 change, kFilePath1, kFile1,
813 SYNC_FILE_TYPE_FILE));
815 // Check if the usage has been increased by (kTestFileData1 - kTestFileData0).
816 const int updated_size =
817 arraysize(kTestFileData1) - arraysize(kTestFileData0);
818 EXPECT_EQ(quota::kQuotaStatusOk,
819 file_system.GetUsageAndQuota(&new_usage, &quota));
820 EXPECT_EQ(updated_size, new_usage - usage);
822 // Apply remote changes to kFile2 and kDir (should create a file and
823 // directory respectively).
824 // They are non-existent yet so their expected file type (the last
825 // parameter of ApplyRemoteChange) are
826 // SYNC_FILE_TYPE_UNKNOWN.
827 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
828 SYNC_FILE_TYPE_FILE);
829 EXPECT_EQ(SYNC_STATUS_OK,
830 ApplyRemoteChange(file_system.file_system_context(),
831 change, kFilePath2, kFile2,
832 SYNC_FILE_TYPE_UNKNOWN));
834 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
835 SYNC_FILE_TYPE_DIRECTORY);
836 EXPECT_EQ(SYNC_STATUS_OK,
837 ApplyRemoteChange(file_system.file_system_context(),
838 change, base::FilePath(), kDir,
839 SYNC_FILE_TYPE_UNKNOWN));
841 // Calling ApplyRemoteChange with different file type should be handled as
842 // overwrite.
843 change =
844 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE);
845 EXPECT_EQ(SYNC_STATUS_OK,
846 ApplyRemoteChange(file_system.file_system_context(),
847 change,
848 kFilePath1,
849 kDir,
850 SYNC_FILE_TYPE_DIRECTORY));
851 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kDir));
853 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
854 SYNC_FILE_TYPE_DIRECTORY);
855 EXPECT_EQ(SYNC_STATUS_OK,
856 ApplyRemoteChange(file_system.file_system_context(),
857 change,
858 kFilePath1,
859 kDir,
860 SYNC_FILE_TYPE_FILE));
862 // Creating a file/directory must have increased the usage more than
863 // the size of kTestFileData2.
864 new_usage = usage;
865 EXPECT_EQ(quota::kQuotaStatusOk,
866 file_system.GetUsageAndQuota(&new_usage, &quota));
867 EXPECT_GT(new_usage,
868 static_cast<int64>(usage + arraysize(kTestFileData2) - 1));
870 // The changes applied by ApplyRemoteChange should not be recorded in
871 // the change tracker.
872 urls.clear();
873 file_system.GetChangedURLsInTracker(&urls);
874 EXPECT_TRUE(urls.empty());
876 // Make sure all three files/directory exist.
877 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile1));
878 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile2));
879 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.DirectoryExists(kDir));
881 sync_context_->ShutdownOnUIThread();
882 file_system.TearDown();
885 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate_NoParent) {
886 base::ScopedTempDir temp_dir;
887 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
889 CannedSyncableFileSystem file_system(GURL(kOrigin1),
890 io_task_runner_.get(),
891 file_task_runner_.get());
892 file_system.SetUp();
894 sync_context_ = new LocalFileSyncContext(
895 dir_.path(), ui_task_runner_.get(), io_task_runner_.get());
896 ASSERT_EQ(SYNC_STATUS_OK,
897 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
898 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem());
900 const char kTestFileData[] = "Lorem ipsum!";
901 const FileSystemURL kDir(file_system.URL("dir"));
902 const FileSystemURL kFile(file_system.URL("dir/file"));
904 // Either kDir or kFile not exist yet.
905 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_system.FileExists(kDir));
906 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_system.FileExists(kFile));
908 // Prepare a temporary file which represents remote file data.
909 const base::FilePath kFilePath(temp_dir.path().Append(FPL("file")));
910 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData) - 1),
911 file_util::WriteFile(kFilePath, kTestFileData,
912 arraysize(kTestFileData) - 1));
914 // Calling ApplyChange's with kFilePath should create
915 // kFile along with kDir.
916 FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
917 SYNC_FILE_TYPE_FILE);
918 EXPECT_EQ(SYNC_STATUS_OK,
919 ApplyRemoteChange(file_system.file_system_context(),
920 change, kFilePath, kFile,
921 SYNC_FILE_TYPE_UNKNOWN));
923 // The changes applied by ApplyRemoteChange should not be recorded in
924 // the change tracker.
925 FileSystemURLSet urls;
926 urls.clear();
927 file_system.GetChangedURLsInTracker(&urls);
928 EXPECT_TRUE(urls.empty());
930 // Make sure kDir and kFile are created by ApplyRemoteChange.
931 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile));
932 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.DirectoryExists(kDir));
934 sync_context_->ShutdownOnUIThread();
935 file_system.TearDown();
938 } // namespace sync_file_system