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