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"
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
{
47 const char kOrigin1
[] = "http://example.com";
48 const char kOrigin2
[] = "http://chromium.org";
51 class LocalFileSyncContextTest
: public testing::Test
{
53 LocalFileSyncContextTest()
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(
69 file_task_runner_
= BrowserThread::GetMessageLoopProxyForThread(
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(
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();
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;
129 *metadata_out
= sync_file_info
.metadata
;
130 *changes_out
= sync_file_info
.changes
;
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 " <<
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();
163 void DidApplyRemoteChange(FileSystemContext
* file_system_context
,
164 const FileSystemURL
& url
,
165 SyncStatusCode 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(
181 base::Bind(&LocalFileSyncContextTest::StartModifyFileOnIOThread
,
182 base::Unretained(this), file_system
, url
));
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();
198 void DidModifyFile(base::PlatformFileError error
) {
199 if (!ui_task_runner_
->RunsTasksOnCurrentThread()) {
200 ASSERT_TRUE(io_task_runner_
->RunsTasksOnCurrentThread());
201 ui_task_runner_
->PostTask(
203 base::Bind(&LocalFileSyncContextTest::DidModifyFile
,
204 base::Unretained(this), error
));
207 ASSERT_TRUE(ui_task_runner_
->RunsTasksOnCurrentThread());
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
));
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());
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());
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());
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());
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
) {
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());
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.
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.
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.
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
);
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
,
497 TEST_F(LocalFileSyncContextTest
, PrepareSync_SyncSuccess_Snapshot
) {
498 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT
,
502 TEST_F(LocalFileSyncContextTest
, PrepareSync_SyncFailure_Exclusive
) {
503 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE
,
507 TEST_F(LocalFileSyncContextTest
, PrepareSync_SyncFailure_Snapshot
) {
508 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT
,
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());
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
;
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
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());
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;
600 EXPECT_EQ(quota::kQuotaStatusOk
,
601 file_system
.GetUsageAndQuota(&initial_usage
, "a
));
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
, "a
));
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.
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
, "a
));
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());
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;
686 EXPECT_EQ(quota::kQuotaStatusOk
,
687 file_system
.GetUsageAndQuota(&initial_usage
, "a
));
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
, "a
));
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
, "a
));
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());
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));
789 int64 usage
= -1, new_usage
= -1;
791 EXPECT_EQ(quota::kQuotaStatusOk
,
792 file_system
.GetUsageAndQuota(&usage
, "a
));
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
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
, "a
));
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
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(),
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(),
860 SYNC_FILE_TYPE_FILE
));
862 // Creating a file/directory must have increased the usage more than
863 // the size of kTestFileData2.
865 EXPECT_EQ(quota::kQuotaStatusOk
,
866 file_system
.GetUsageAndQuota(&new_usage
, "a
));
868 static_cast<int64
>(usage
+ arraysize(kTestFileData2
) - 1));
870 // The changes applied by ApplyRemoteChange should not be recorded in
871 // the change tracker.
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());
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
;
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