Refactor WebsiteSettings to operate on a SecurityInfo
[chromium-blink-merge.git] / chrome / browser / sync_file_system / local / local_file_sync_context_unittest.cc
blob46f4c6d49ee2718a707fcee7b813c0d881cd9c02
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/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 {
49 namespace {
50 const char kOrigin1[] = "http://example.com";
51 const char kOrigin2[] = "http://chromium.org";
54 class LocalFileSyncContextTest : public testing::Test {
55 protected:
56 LocalFileSyncContextTest()
57 : thread_bundle_(
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(
72 BrowserThread::IO);
73 file_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
74 BrowserThread::IO);
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(
90 file_system_context,
91 url,
92 sync_mode,
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();
106 return status_;
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;
130 status_ = status;
131 *metadata_out = sync_file_info.metadata;
132 *changes_out = sync_file_info.changes;
133 if (snapshot_out)
134 *snapshot_out = snapshot.Pass();
135 base::MessageLoop::current()->Quit();
138 SyncStatusCode ApplyRemoteChange(FileSystemContext* file_system_context,
139 const FileChange& change,
140 const base::FilePath& local_path,
141 const FileSystemURL& url,
142 SyncFileType expected_file_type) {
143 SCOPED_TRACE(testing::Message() << "ApplyChange for " <<
144 url.DebugString());
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();
162 return status_;
165 void DidApplyRemoteChange(FileSystemContext* file_system_context,
166 const FileSystemURL& url,
167 SyncStatusCode status) {
168 status_ = status;
169 sync_context_->FinalizeExclusiveSync(
170 file_system_context, url,
171 status == SYNC_STATUS_OK /* clear_local_changes */,
172 base::MessageLoop::QuitClosure());
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(
182 FROM_HERE,
183 base::Bind(&LocalFileSyncContextTest::StartModifyFileOnIOThread,
184 base::Unretained(this), file_system, url));
185 return;
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();
197 return file_error_;
200 void DidModifyFile(base::File::Error error) {
201 if (!ui_task_runner_->RunsTasksOnCurrentThread()) {
202 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
203 ui_task_runner_->PostTask(
204 FROM_HERE,
205 base::Bind(&LocalFileSyncContextTest::DidModifyFile,
206 base::Unretained(this), error));
207 return;
209 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
210 file_error_ = error;
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));
222 } else {
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());
270 } else {
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());
324 } else {
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) {
366 sync_context_ =
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.
454 urls.clear();
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.
462 urls.clear();
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.
468 urls.clear();
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);
485 changes.clear();
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,
505 SYNC_STATUS_OK);
508 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Snapshot) {
509 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
510 SYNC_STATUS_OK);
513 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Exclusive) {
514 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
515 SYNC_STATUS_FAILED);
518 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Snapshot) {
519 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
520 SYNC_STATUS_FAILED);
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;
571 changes.clear();
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
581 // is done.
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;
614 int64 quota = -1;
615 EXPECT_EQ(storage::kQuotaStatusOk,
616 file_system.GetUsageAndQuota(&initial_usage, &quota));
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, &quota));
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.
672 urls.clear();
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, &quota));
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;
702 int64 quota = -1;
703 EXPECT_EQ(storage::kQuotaStatusOk,
704 file_system.GetUsageAndQuota(&initial_usage, &quota));
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, &quota));
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, &quota));
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));
807 // Record the usage.
808 int64 usage = -1, new_usage = -1;
809 int64 quota = -1;
810 EXPECT_EQ(storage::kQuotaStatusOk,
811 file_system.GetUsageAndQuota(&usage, &quota));
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
819 // * kDir
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, &quota));
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
861 // overwrite.
862 change =
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(),
866 change,
867 kFilePath1,
868 kDir,
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(),
876 change,
877 kFilePath1,
878 kDir,
879 SYNC_FILE_TYPE_FILE));
881 // Creating a file/directory must have increased the usage more than
882 // the size of kTestFileData2.
883 new_usage = usage;
884 EXPECT_EQ(storage::kQuotaStatusOk,
885 file_system.GetUsageAndQuota(&new_usage, &quota));
886 EXPECT_GT(new_usage,
887 static_cast<int64>(usage + arraysize(kTestFileData2) - 1));
889 // The changes applied by ApplyRemoteChange should not be recorded in
890 // the change tracker.
891 urls.clear();
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;
947 urls.clear();
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