Fix infinite recursion on hiding panel when created during fullscreen mode.
[chromium-blink-merge.git] / chrome / browser / sync_file_system / local / local_file_sync_context_unittest.cc
bloba5320370bab65016d988eea9a96bc8b0e5ce6713
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h"
7 #include <vector>
9 #include "base/bind.h"
10 #include "base/bind_helpers.h"
11 #include "base/file_util.h"
12 #include "base/files/file_path.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/platform_file.h"
15 #include "base/stl_util.h"
16 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h"
17 #include "chrome/browser/sync_file_system/local/local_file_change_tracker.h"
18 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h"
19 #include "chrome/browser/sync_file_system/sync_file_metadata.h"
20 #include "chrome/browser/sync_file_system/sync_status_code.h"
21 #include "chrome/browser/sync_file_system/syncable_file_system_util.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/test/mock_blob_url_request_context.h"
24 #include "content/public/test/test_browser_thread_bundle.h"
25 #include "testing/gtest/include/gtest/gtest.h"
26 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h"
27 #include "third_party/leveldatabase/src/include/leveldb/env.h"
28 #include "webkit/browser/fileapi/file_system_context.h"
29 #include "webkit/browser/fileapi/file_system_operation_runner.h"
30 #include "webkit/browser/fileapi/isolated_context.h"
31 #include "webkit/common/blob/scoped_file.h"
33 #define FPL FILE_PATH_LITERAL
35 using content::BrowserThread;
36 using fileapi::FileSystemContext;
37 using fileapi::FileSystemURL;
38 using fileapi::FileSystemURLSet;
40 // This tests LocalFileSyncContext behavior in multi-thread /
41 // multi-file-system-context environment.
42 // Basic combined tests (single-thread / single-file-system-context)
43 // that involve LocalFileSyncContext are also in
44 // syncable_file_system_unittests.cc.
46 namespace sync_file_system {
48 namespace {
49 const char kOrigin1[] = "http://example.com";
50 const char kOrigin2[] = "http://chromium.org";
53 class LocalFileSyncContextTest : public testing::Test {
54 protected:
55 LocalFileSyncContextTest()
56 : thread_bundle_(
57 content::TestBrowserThreadBundle::REAL_FILE_THREAD |
58 content::TestBrowserThreadBundle::REAL_IO_THREAD),
59 status_(SYNC_FILE_ERROR_FAILED),
60 file_error_(base::File::FILE_ERROR_FAILED),
61 async_modify_finished_(false),
62 has_inflight_prepare_for_sync_(false) {}
64 virtual void SetUp() OVERRIDE {
65 RegisterSyncableFileSystem();
66 ASSERT_TRUE(dir_.CreateUniqueTempDir());
67 in_memory_env_.reset(leveldb::NewMemEnv(leveldb::Env::Default()));
69 ui_task_runner_ = base::MessageLoop::current()->message_loop_proxy();
70 io_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
71 BrowserThread::IO);
72 file_task_runner_ = BrowserThread::GetMessageLoopProxyForThread(
73 BrowserThread::IO);
76 virtual void TearDown() OVERRIDE {
77 RevokeSyncableFileSystem();
80 void StartPrepareForSync(FileSystemContext* file_system_context,
81 const FileSystemURL& url,
82 LocalFileSyncContext::SyncMode sync_mode,
83 SyncFileMetadata* metadata,
84 FileChangeList* changes,
85 webkit_blob::ScopedFile* snapshot) {
86 ASSERT_TRUE(changes != NULL);
87 ASSERT_FALSE(has_inflight_prepare_for_sync_);
88 status_ = SYNC_STATUS_UNKNOWN;
89 has_inflight_prepare_for_sync_ = true;
90 sync_context_->PrepareForSync(
91 file_system_context,
92 url,
93 sync_mode,
94 base::Bind(&LocalFileSyncContextTest::DidPrepareForSync,
95 base::Unretained(this), metadata, changes, snapshot));
98 SyncStatusCode PrepareForSync(FileSystemContext* file_system_context,
99 const FileSystemURL& url,
100 LocalFileSyncContext::SyncMode sync_mode,
101 SyncFileMetadata* metadata,
102 FileChangeList* changes,
103 webkit_blob::ScopedFile* snapshot) {
104 StartPrepareForSync(file_system_context, url, sync_mode,
105 metadata, changes, snapshot);
106 base::MessageLoop::current()->Run();
107 return status_;
110 base::Closure GetPrepareForSyncClosure(
111 FileSystemContext* file_system_context,
112 const FileSystemURL& url,
113 LocalFileSyncContext::SyncMode sync_mode,
114 SyncFileMetadata* metadata,
115 FileChangeList* changes,
116 webkit_blob::ScopedFile* snapshot) {
117 return base::Bind(&LocalFileSyncContextTest::StartPrepareForSync,
118 base::Unretained(this),
119 base::Unretained(file_system_context),
120 url, sync_mode, metadata, changes, snapshot);
123 void DidPrepareForSync(SyncFileMetadata* metadata_out,
124 FileChangeList* changes_out,
125 webkit_blob::ScopedFile* snapshot_out,
126 SyncStatusCode status,
127 const LocalFileSyncInfo& sync_file_info,
128 webkit_blob::ScopedFile snapshot) {
129 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
130 has_inflight_prepare_for_sync_ = false;
131 status_ = status;
132 *metadata_out = sync_file_info.metadata;
133 *changes_out = sync_file_info.changes;
134 if (snapshot_out)
135 *snapshot_out = snapshot.Pass();
136 base::MessageLoop::current()->Quit();
139 SyncStatusCode ApplyRemoteChange(FileSystemContext* file_system_context,
140 const FileChange& change,
141 const base::FilePath& local_path,
142 const FileSystemURL& url,
143 SyncFileType expected_file_type) {
144 SCOPED_TRACE(testing::Message() << "ApplyChange for " <<
145 url.DebugString());
147 // First we should call PrepareForSync to disable writing.
148 SyncFileMetadata metadata;
149 FileChangeList changes;
150 EXPECT_EQ(SYNC_STATUS_OK,
151 PrepareForSync(file_system_context, url,
152 LocalFileSyncContext::SYNC_EXCLUSIVE,
153 &metadata, &changes, NULL));
154 EXPECT_EQ(expected_file_type, metadata.file_type);
156 status_ = SYNC_STATUS_UNKNOWN;
157 sync_context_->ApplyRemoteChange(
158 file_system_context, change, local_path, url,
159 base::Bind(&LocalFileSyncContextTest::DidApplyRemoteChange,
160 base::Unretained(this),
161 make_scoped_refptr(file_system_context), url));
162 base::MessageLoop::current()->Run();
163 return status_;
166 void DidApplyRemoteChange(FileSystemContext* file_system_context,
167 const FileSystemURL& url,
168 SyncStatusCode status) {
169 status_ = status;
170 sync_context_->FinalizeExclusiveSync(
171 file_system_context, url,
172 status == SYNC_STATUS_OK /* clear_local_changes */,
173 base::MessageLoop::QuitClosure());
176 void StartModifyFileOnIOThread(CannedSyncableFileSystem* file_system,
177 const FileSystemURL& url) {
178 ASSERT_TRUE(file_system != NULL);
179 if (!io_task_runner_->RunsTasksOnCurrentThread()) {
180 async_modify_finished_ = false;
181 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
182 io_task_runner_->PostTask(
183 FROM_HERE,
184 base::Bind(&LocalFileSyncContextTest::StartModifyFileOnIOThread,
185 base::Unretained(this), file_system, url));
186 return;
188 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
189 file_error_ = base::File::FILE_ERROR_FAILED;
190 file_system->operation_runner()->Truncate(
191 url, 1, base::Bind(&LocalFileSyncContextTest::DidModifyFile,
192 base::Unretained(this)));
195 base::File::Error WaitUntilModifyFileIsDone() {
196 while (!async_modify_finished_)
197 base::MessageLoop::current()->RunUntilIdle();
198 return file_error_;
201 void DidModifyFile(base::File::Error error) {
202 if (!ui_task_runner_->RunsTasksOnCurrentThread()) {
203 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread());
204 ui_task_runner_->PostTask(
205 FROM_HERE,
206 base::Bind(&LocalFileSyncContextTest::DidModifyFile,
207 base::Unretained(this), error));
208 return;
210 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread());
211 file_error_ = error;
212 async_modify_finished_ = true;
215 void SimulateFinishSync(FileSystemContext* file_system_context,
216 const FileSystemURL& url,
217 SyncStatusCode status,
218 LocalFileSyncContext::SyncMode sync_mode) {
219 if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) {
220 sync_context_->FinalizeSnapshotSync(
221 file_system_context, url, status,
222 base::Bind(&base::DoNothing));
223 } else {
224 sync_context_->FinalizeExclusiveSync(
225 file_system_context, url,
226 status == SYNC_STATUS_OK /* clear_local_changes */,
227 base::Bind(&base::DoNothing));
231 void PrepareForSync_Basic(LocalFileSyncContext::SyncMode sync_mode,
232 SyncStatusCode simulate_sync_finish_status) {
233 CannedSyncableFileSystem file_system(GURL(kOrigin1),
234 in_memory_env_.get(),
235 io_task_runner_.get(),
236 file_task_runner_.get());
237 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
238 sync_context_ = new LocalFileSyncContext(
239 dir_.path(), in_memory_env_.get(),
240 ui_task_runner_.get(), io_task_runner_.get());
241 ASSERT_EQ(SYNC_STATUS_OK,
242 file_system.MaybeInitializeFileSystemContext(
243 sync_context_.get()));
244 ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
246 const FileSystemURL kFile(file_system.URL("file"));
247 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
249 SyncFileMetadata metadata;
250 FileChangeList changes;
251 EXPECT_EQ(SYNC_STATUS_OK,
252 PrepareForSync(file_system.file_system_context(), kFile,
253 sync_mode, &metadata, &changes, NULL));
254 EXPECT_EQ(1U, changes.size());
255 EXPECT_TRUE(changes.list().back().IsFile());
256 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
258 // We should see the same set of changes.
259 file_system.GetChangesForURLInTracker(kFile, &changes);
260 EXPECT_EQ(1U, changes.size());
261 EXPECT_TRUE(changes.list().back().IsFile());
262 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
264 SimulateFinishSync(file_system.file_system_context(), kFile,
265 simulate_sync_finish_status, sync_mode);
267 file_system.GetChangesForURLInTracker(kFile, &changes);
268 if (simulate_sync_finish_status == SYNC_STATUS_OK) {
269 // The change's cleared.
270 EXPECT_TRUE(changes.empty());
271 } else {
272 EXPECT_EQ(1U, changes.size());
273 EXPECT_TRUE(changes.list().back().IsFile());
274 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
277 sync_context_->ShutdownOnUIThread();
278 sync_context_ = NULL;
280 file_system.TearDown();
283 void PrepareForSync_WriteDuringSync(
284 LocalFileSyncContext::SyncMode sync_mode) {
285 CannedSyncableFileSystem file_system(GURL(kOrigin1),
286 in_memory_env_.get(),
287 io_task_runner_.get(),
288 file_task_runner_.get());
289 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
290 sync_context_ = new LocalFileSyncContext(
291 dir_.path(), in_memory_env_.get(),
292 ui_task_runner_.get(), io_task_runner_.get());
293 ASSERT_EQ(SYNC_STATUS_OK,
294 file_system.MaybeInitializeFileSystemContext(
295 sync_context_.get()));
296 ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
298 const FileSystemURL kFile(file_system.URL("file"));
299 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
301 SyncFileMetadata metadata;
302 FileChangeList changes;
303 webkit_blob::ScopedFile snapshot;
304 EXPECT_EQ(SYNC_STATUS_OK,
305 PrepareForSync(file_system.file_system_context(), kFile,
306 sync_mode, &metadata, &changes, &snapshot));
307 EXPECT_EQ(1U, changes.size());
308 EXPECT_TRUE(changes.list().back().IsFile());
309 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
311 EXPECT_EQ(sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT,
312 !snapshot.path().empty());
314 // Tracker keeps same set of changes.
315 file_system.GetChangesForURLInTracker(kFile, &changes);
316 EXPECT_EQ(1U, changes.size());
317 EXPECT_TRUE(changes.list().back().IsFile());
318 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
320 StartModifyFileOnIOThread(&file_system, kFile);
322 if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) {
323 // Write should succeed.
324 EXPECT_EQ(base::File::FILE_OK, WaitUntilModifyFileIsDone());
325 } else {
326 base::MessageLoop::current()->RunUntilIdle();
327 EXPECT_FALSE(async_modify_finished_);
330 SimulateFinishSync(file_system.file_system_context(), kFile,
331 SYNC_STATUS_OK, sync_mode);
333 EXPECT_EQ(base::File::FILE_OK, WaitUntilModifyFileIsDone());
335 // Sync succeeded, but the other change that was made during or
336 // after sync is recorded.
337 file_system.GetChangesForURLInTracker(kFile, &changes);
338 EXPECT_EQ(1U, changes.size());
339 EXPECT_TRUE(changes.list().back().IsFile());
340 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
342 sync_context_->ShutdownOnUIThread();
343 sync_context_ = NULL;
345 file_system.TearDown();
348 ScopedEnableSyncFSDirectoryOperation enable_directory_operation_;
350 base::ScopedTempDir dir_;
351 scoped_ptr<leveldb::Env> in_memory_env_;
353 // These need to remain until the very end.
354 content::TestBrowserThreadBundle thread_bundle_;
356 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
357 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
358 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
360 scoped_refptr<LocalFileSyncContext> sync_context_;
362 SyncStatusCode status_;
363 base::File::Error file_error_;
364 bool async_modify_finished_;
365 bool has_inflight_prepare_for_sync_;
368 TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) {
369 sync_context_ =
370 new LocalFileSyncContext(
371 dir_.path(), in_memory_env_.get(),
372 ui_task_runner_.get(), io_task_runner_.get());
373 sync_context_->ShutdownOnUIThread();
376 TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) {
377 CannedSyncableFileSystem file_system(GURL(kOrigin1),
378 in_memory_env_.get(),
379 io_task_runner_.get(),
380 file_task_runner_.get());
381 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
383 sync_context_ = new LocalFileSyncContext(
384 dir_.path(), in_memory_env_.get(),
385 ui_task_runner_.get(), io_task_runner_.get());
387 // Initializes file_system using |sync_context_|.
388 EXPECT_EQ(SYNC_STATUS_OK,
389 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
391 // Make sure everything's set up for file_system to be able to handle
392 // syncable file system operations.
393 EXPECT_TRUE(file_system.backend()->sync_context() != NULL);
394 EXPECT_TRUE(file_system.backend()->change_tracker() != NULL);
395 EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context());
397 // Calling MaybeInitialize for the same context multiple times must be ok.
398 EXPECT_EQ(SYNC_STATUS_OK,
399 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
400 EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context());
402 // Opens the file_system, perform some operation and see if the change tracker
403 // correctly captures the change.
404 EXPECT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
406 const FileSystemURL kURL(file_system.URL("foo"));
407 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kURL));
409 FileSystemURLSet urls;
410 file_system.GetChangedURLsInTracker(&urls);
411 ASSERT_EQ(1U, urls.size());
412 EXPECT_TRUE(ContainsKey(urls, kURL));
414 // Finishing the test.
415 sync_context_->ShutdownOnUIThread();
416 file_system.TearDown();
419 TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) {
420 CannedSyncableFileSystem file_system1(GURL(kOrigin1),
421 in_memory_env_.get(),
422 io_task_runner_.get(),
423 file_task_runner_.get());
424 CannedSyncableFileSystem file_system2(GURL(kOrigin2),
425 in_memory_env_.get(),
426 io_task_runner_.get(),
427 file_task_runner_.get());
428 file_system1.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
429 file_system2.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
431 sync_context_ = new LocalFileSyncContext(
432 dir_.path(), in_memory_env_.get(),
433 ui_task_runner_.get(), io_task_runner_.get());
435 // Initializes file_system1 and file_system2.
436 EXPECT_EQ(SYNC_STATUS_OK,
437 file_system1.MaybeInitializeFileSystemContext(sync_context_.get()));
438 EXPECT_EQ(SYNC_STATUS_OK,
439 file_system2.MaybeInitializeFileSystemContext(sync_context_.get()));
441 EXPECT_EQ(base::File::FILE_OK, file_system1.OpenFileSystem());
442 EXPECT_EQ(base::File::FILE_OK, file_system2.OpenFileSystem());
444 const FileSystemURL kURL1(file_system1.URL("foo"));
445 const FileSystemURL kURL2(file_system2.URL("bar"));
447 // Creates a file in file_system1.
448 EXPECT_EQ(base::File::FILE_OK, file_system1.CreateFile(kURL1));
450 // file_system1's tracker must have recorded the change.
451 FileSystemURLSet urls;
452 file_system1.GetChangedURLsInTracker(&urls);
453 ASSERT_EQ(1U, urls.size());
454 EXPECT_TRUE(ContainsKey(urls, kURL1));
456 // file_system1's tracker must have no change.
457 urls.clear();
458 file_system2.GetChangedURLsInTracker(&urls);
459 ASSERT_TRUE(urls.empty());
461 // Creates a directory in file_system2.
462 EXPECT_EQ(base::File::FILE_OK, file_system2.CreateDirectory(kURL2));
464 // file_system1's tracker must have the change for kURL1 as before.
465 urls.clear();
466 file_system1.GetChangedURLsInTracker(&urls);
467 ASSERT_EQ(1U, urls.size());
468 EXPECT_TRUE(ContainsKey(urls, kURL1));
470 // file_system2's tracker now must have the change for kURL2.
471 urls.clear();
472 file_system2.GetChangedURLsInTracker(&urls);
473 ASSERT_EQ(1U, urls.size());
474 EXPECT_TRUE(ContainsKey(urls, kURL2));
476 SyncFileMetadata metadata;
477 FileChangeList changes;
478 EXPECT_EQ(SYNC_STATUS_OK,
479 PrepareForSync(file_system1.file_system_context(), kURL1,
480 LocalFileSyncContext::SYNC_EXCLUSIVE,
481 &metadata, &changes, NULL));
482 EXPECT_EQ(1U, changes.size());
483 EXPECT_TRUE(changes.list().back().IsFile());
484 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
485 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
486 EXPECT_EQ(0, metadata.size);
488 changes.clear();
489 EXPECT_EQ(SYNC_STATUS_OK,
490 PrepareForSync(file_system2.file_system_context(), kURL2,
491 LocalFileSyncContext::SYNC_EXCLUSIVE,
492 &metadata, &changes, NULL));
493 EXPECT_EQ(1U, changes.size());
494 EXPECT_FALSE(changes.list().back().IsFile());
495 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
496 EXPECT_EQ(SYNC_FILE_TYPE_DIRECTORY, metadata.file_type);
497 EXPECT_EQ(0, metadata.size);
499 sync_context_->ShutdownOnUIThread();
500 sync_context_ = NULL;
502 file_system1.TearDown();
503 file_system2.TearDown();
506 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Exclusive) {
507 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
508 SYNC_STATUS_OK);
511 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Snapshot) {
512 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
513 SYNC_STATUS_OK);
516 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Exclusive) {
517 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE,
518 SYNC_STATUS_FAILED);
521 TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Snapshot) {
522 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT,
523 SYNC_STATUS_FAILED);
526 TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Exclusive) {
527 PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_EXCLUSIVE);
530 TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Snapshot) {
531 PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_SNAPSHOT);
534 // LocalFileSyncContextTest.PrepareSyncWhileWriting is flaky on android.
535 // http://crbug.com/239793
536 // It is also flaky on the TSAN v2 bots, and hangs other bots.
537 // http://crbug.com/305905.
538 TEST_F(LocalFileSyncContextTest, DISABLED_PrepareSyncWhileWriting) {
539 CannedSyncableFileSystem file_system(GURL(kOrigin1),
540 in_memory_env_.get(),
541 io_task_runner_.get(),
542 file_task_runner_.get());
543 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
544 sync_context_ = new LocalFileSyncContext(
545 dir_.path(), in_memory_env_.get(),
546 ui_task_runner_.get(), io_task_runner_.get());
547 EXPECT_EQ(SYNC_STATUS_OK,
548 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
550 EXPECT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
552 const FileSystemURL kURL1(file_system.URL("foo"));
554 // Creates a file in file_system.
555 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kURL1));
557 // Kick file write on IO thread.
558 StartModifyFileOnIOThread(&file_system, kURL1);
560 // Until the operation finishes PrepareForSync should return BUSY error.
561 SyncFileMetadata metadata;
562 metadata.file_type = SYNC_FILE_TYPE_UNKNOWN;
563 FileChangeList changes;
564 EXPECT_EQ(SYNC_STATUS_FILE_BUSY,
565 PrepareForSync(file_system.file_system_context(), kURL1,
566 LocalFileSyncContext::SYNC_EXCLUSIVE,
567 &metadata, &changes, NULL));
568 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
570 // Register PrepareForSync method to be invoked when kURL1 becomes
571 // syncable. (Actually this may be done after all operations are done
572 // on IO thread in this test.)
573 metadata.file_type = SYNC_FILE_TYPE_UNKNOWN;
574 changes.clear();
575 sync_context_->RegisterURLForWaitingSync(
576 kURL1, GetPrepareForSyncClosure(file_system.file_system_context(), kURL1,
577 LocalFileSyncContext::SYNC_EXCLUSIVE,
578 &metadata, &changes, NULL));
580 // Wait for the completion.
581 EXPECT_EQ(base::File::FILE_OK, WaitUntilModifyFileIsDone());
583 // The PrepareForSync must have been started; wait until DidPrepareForSync
584 // is done.
585 base::MessageLoop::current()->Run();
586 ASSERT_FALSE(has_inflight_prepare_for_sync_);
588 // Now PrepareForSync should have run and returned OK.
589 EXPECT_EQ(SYNC_STATUS_OK, status_);
590 EXPECT_EQ(1U, changes.size());
591 EXPECT_TRUE(changes.list().back().IsFile());
592 EXPECT_TRUE(changes.list().back().IsAddOrUpdate());
593 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type);
594 EXPECT_EQ(1, metadata.size);
596 sync_context_->ShutdownOnUIThread();
597 sync_context_ = NULL;
598 file_system.TearDown();
601 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion) {
602 CannedSyncableFileSystem file_system(GURL(kOrigin1),
603 in_memory_env_.get(),
604 io_task_runner_.get(),
605 file_task_runner_.get());
606 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
608 sync_context_ = new LocalFileSyncContext(
609 dir_.path(), in_memory_env_.get(),
610 ui_task_runner_.get(), io_task_runner_.get());
611 ASSERT_EQ(SYNC_STATUS_OK,
612 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
613 ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
615 // Record the initial usage (likely 0).
616 int64 initial_usage = -1;
617 int64 quota = -1;
618 EXPECT_EQ(quota::kQuotaStatusOk,
619 file_system.GetUsageAndQuota(&initial_usage, &quota));
621 // Create a file and directory in the file_system.
622 const FileSystemURL kFile(file_system.URL("file"));
623 const FileSystemURL kDir(file_system.URL("dir"));
624 const FileSystemURL kChild(file_system.URL("dir/child"));
626 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
627 EXPECT_EQ(base::File::FILE_OK, file_system.CreateDirectory(kDir));
628 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kChild));
630 // file_system's change tracker must have recorded the creation.
631 FileSystemURLSet urls;
632 file_system.GetChangedURLsInTracker(&urls);
633 ASSERT_EQ(3U, urls.size());
634 ASSERT_TRUE(ContainsKey(urls, kFile));
635 ASSERT_TRUE(ContainsKey(urls, kDir));
636 ASSERT_TRUE(ContainsKey(urls, kChild));
637 for (FileSystemURLSet::iterator iter = urls.begin();
638 iter != urls.end(); ++iter) {
639 file_system.ClearChangeForURLInTracker(*iter);
642 // At this point the usage must be greater than the initial usage.
643 int64 new_usage = -1;
644 EXPECT_EQ(quota::kQuotaStatusOk,
645 file_system.GetUsageAndQuota(&new_usage, &quota));
646 EXPECT_GT(new_usage, initial_usage);
648 // Now let's apply remote deletion changes.
649 FileChange change(FileChange::FILE_CHANGE_DELETE,
650 SYNC_FILE_TYPE_FILE);
651 EXPECT_EQ(SYNC_STATUS_OK,
652 ApplyRemoteChange(file_system.file_system_context(),
653 change, base::FilePath(), kFile,
654 SYNC_FILE_TYPE_FILE));
656 // The implementation doesn't check file type for deletion, and it must be ok
657 // even if we don't know if the deletion change was for a file or a directory.
658 change = FileChange(FileChange::FILE_CHANGE_DELETE,
659 SYNC_FILE_TYPE_UNKNOWN);
660 EXPECT_EQ(SYNC_STATUS_OK,
661 ApplyRemoteChange(file_system.file_system_context(),
662 change, base::FilePath(), kDir,
663 SYNC_FILE_TYPE_DIRECTORY));
665 // Check the directory/files are deleted successfully.
666 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
667 file_system.FileExists(kFile));
668 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
669 file_system.DirectoryExists(kDir));
670 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
671 file_system.FileExists(kChild));
673 // The changes applied by ApplyRemoteChange should not be recorded in
674 // the change tracker.
675 urls.clear();
676 file_system.GetChangedURLsInTracker(&urls);
677 EXPECT_TRUE(urls.empty());
679 // The quota usage data must have reflected the deletion.
680 EXPECT_EQ(quota::kQuotaStatusOk,
681 file_system.GetUsageAndQuota(&new_usage, &quota));
682 EXPECT_EQ(new_usage, initial_usage);
684 sync_context_->ShutdownOnUIThread();
685 sync_context_ = NULL;
686 file_system.TearDown();
689 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion_ForRoot) {
690 CannedSyncableFileSystem file_system(GURL(kOrigin1),
691 in_memory_env_.get(),
692 io_task_runner_.get(),
693 file_task_runner_.get());
694 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
696 sync_context_ = new LocalFileSyncContext(
697 dir_.path(), in_memory_env_.get(),
698 ui_task_runner_.get(), io_task_runner_.get());
699 ASSERT_EQ(SYNC_STATUS_OK,
700 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
701 ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
703 // Record the initial usage (likely 0).
704 int64 initial_usage = -1;
705 int64 quota = -1;
706 EXPECT_EQ(quota::kQuotaStatusOk,
707 file_system.GetUsageAndQuota(&initial_usage, &quota));
709 // Create a file and directory in the file_system.
710 const FileSystemURL kFile(file_system.URL("file"));
711 const FileSystemURL kDir(file_system.URL("dir"));
712 const FileSystemURL kChild(file_system.URL("dir/child"));
714 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile));
715 EXPECT_EQ(base::File::FILE_OK, file_system.CreateDirectory(kDir));
716 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kChild));
718 // At this point the usage must be greater than the initial usage.
719 int64 new_usage = -1;
720 EXPECT_EQ(quota::kQuotaStatusOk,
721 file_system.GetUsageAndQuota(&new_usage, &quota));
722 EXPECT_GT(new_usage, initial_usage);
724 const FileSystemURL kRoot(file_system.URL(""));
726 // Now let's apply remote deletion changes for the root.
727 FileChange change(FileChange::FILE_CHANGE_DELETE, SYNC_FILE_TYPE_DIRECTORY);
728 EXPECT_EQ(SYNC_STATUS_OK,
729 ApplyRemoteChange(file_system.file_system_context(),
730 change, base::FilePath(), kRoot,
731 SYNC_FILE_TYPE_DIRECTORY));
733 // Check the directory/files are deleted successfully.
734 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
735 file_system.FileExists(kFile));
736 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
737 file_system.DirectoryExists(kDir));
738 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
739 file_system.FileExists(kChild));
741 // All changes made for the previous creation must have been also reset.
742 FileSystemURLSet urls;
743 file_system.GetChangedURLsInTracker(&urls);
744 EXPECT_TRUE(urls.empty());
746 // The quota usage data must have reflected the deletion.
747 EXPECT_EQ(quota::kQuotaStatusOk,
748 file_system.GetUsageAndQuota(&new_usage, &quota));
749 EXPECT_EQ(new_usage, initial_usage);
751 sync_context_->ShutdownOnUIThread();
752 sync_context_ = NULL;
753 file_system.TearDown();
756 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate) {
757 base::ScopedTempDir temp_dir;
758 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
760 CannedSyncableFileSystem file_system(GURL(kOrigin1),
761 in_memory_env_.get(),
762 io_task_runner_.get(),
763 file_task_runner_.get());
764 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
766 sync_context_ = new LocalFileSyncContext(
767 dir_.path(), in_memory_env_.get(),
768 ui_task_runner_.get(), io_task_runner_.get());
769 ASSERT_EQ(SYNC_STATUS_OK,
770 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
771 ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
773 const FileSystemURL kFile1(file_system.URL("file1"));
774 const FileSystemURL kFile2(file_system.URL("file2"));
775 const FileSystemURL kDir(file_system.URL("dir"));
777 const char kTestFileData0[] = "0123456789";
778 const char kTestFileData1[] = "Lorem ipsum!";
779 const char kTestFileData2[] = "This is sample test data.";
781 // Create kFile1 and populate it with kTestFileData0.
782 EXPECT_EQ(base::File::FILE_OK, file_system.CreateFile(kFile1));
783 EXPECT_EQ(static_cast<int64>(arraysize(kTestFileData0) - 1),
784 file_system.WriteString(kFile1, kTestFileData0));
786 // kFile2 and kDir are not there yet.
787 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
788 file_system.FileExists(kFile2));
789 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND,
790 file_system.DirectoryExists(kDir));
792 // file_system's change tracker must have recorded the creation.
793 FileSystemURLSet urls;
794 file_system.GetChangedURLsInTracker(&urls);
795 ASSERT_EQ(1U, urls.size());
796 EXPECT_TRUE(ContainsKey(urls, kFile1));
797 file_system.ClearChangeForURLInTracker(*urls.begin());
799 // Prepare temporary files which represent the remote file data.
800 const base::FilePath kFilePath1(temp_dir.path().Append(FPL("file1")));
801 const base::FilePath kFilePath2(temp_dir.path().Append(FPL("file2")));
803 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData1) - 1),
804 base::WriteFile(kFilePath1, kTestFileData1,
805 arraysize(kTestFileData1) - 1));
806 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData2) - 1),
807 base::WriteFile(kFilePath2, kTestFileData2,
808 arraysize(kTestFileData2) - 1));
810 // Record the usage.
811 int64 usage = -1, new_usage = -1;
812 int64 quota = -1;
813 EXPECT_EQ(quota::kQuotaStatusOk,
814 file_system.GetUsageAndQuota(&usage, &quota));
816 // Here in the local filesystem we have:
817 // * kFile1 with kTestFileData0
819 // In the remote side let's assume we have:
820 // * kFile1 with kTestFileData1
821 // * kFile2 with kTestFileData2
822 // * kDir
824 // By calling ApplyChange's:
825 // * kFile1 will be updated to have kTestFileData1
826 // * kFile2 will be created
827 // * kDir will be created
829 // Apply the remote change to kFile1 (which will update the file).
830 FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
831 SYNC_FILE_TYPE_FILE);
832 EXPECT_EQ(SYNC_STATUS_OK,
833 ApplyRemoteChange(file_system.file_system_context(),
834 change, kFilePath1, kFile1,
835 SYNC_FILE_TYPE_FILE));
837 // Check if the usage has been increased by (kTestFileData1 - kTestFileData0).
838 const int updated_size =
839 arraysize(kTestFileData1) - arraysize(kTestFileData0);
840 EXPECT_EQ(quota::kQuotaStatusOk,
841 file_system.GetUsageAndQuota(&new_usage, &quota));
842 EXPECT_EQ(updated_size, new_usage - usage);
844 // Apply remote changes to kFile2 and kDir (should create a file and
845 // directory respectively).
846 // They are non-existent yet so their expected file type (the last
847 // parameter of ApplyRemoteChange) are
848 // SYNC_FILE_TYPE_UNKNOWN.
849 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
850 SYNC_FILE_TYPE_FILE);
851 EXPECT_EQ(SYNC_STATUS_OK,
852 ApplyRemoteChange(file_system.file_system_context(),
853 change, kFilePath2, kFile2,
854 SYNC_FILE_TYPE_UNKNOWN));
856 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
857 SYNC_FILE_TYPE_DIRECTORY);
858 EXPECT_EQ(SYNC_STATUS_OK,
859 ApplyRemoteChange(file_system.file_system_context(),
860 change, base::FilePath(), kDir,
861 SYNC_FILE_TYPE_UNKNOWN));
863 // Calling ApplyRemoteChange with different file type should be handled as
864 // overwrite.
865 change =
866 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE);
867 EXPECT_EQ(SYNC_STATUS_OK,
868 ApplyRemoteChange(file_system.file_system_context(),
869 change,
870 kFilePath1,
871 kDir,
872 SYNC_FILE_TYPE_DIRECTORY));
873 EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kDir));
875 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
876 SYNC_FILE_TYPE_DIRECTORY);
877 EXPECT_EQ(SYNC_STATUS_OK,
878 ApplyRemoteChange(file_system.file_system_context(),
879 change,
880 kFilePath1,
881 kDir,
882 SYNC_FILE_TYPE_FILE));
884 // Creating a file/directory must have increased the usage more than
885 // the size of kTestFileData2.
886 new_usage = usage;
887 EXPECT_EQ(quota::kQuotaStatusOk,
888 file_system.GetUsageAndQuota(&new_usage, &quota));
889 EXPECT_GT(new_usage,
890 static_cast<int64>(usage + arraysize(kTestFileData2) - 1));
892 // The changes applied by ApplyRemoteChange should not be recorded in
893 // the change tracker.
894 urls.clear();
895 file_system.GetChangedURLsInTracker(&urls);
896 EXPECT_TRUE(urls.empty());
898 // Make sure all three files/directory exist.
899 EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kFile1));
900 EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kFile2));
901 EXPECT_EQ(base::File::FILE_OK, file_system.DirectoryExists(kDir));
903 sync_context_->ShutdownOnUIThread();
904 file_system.TearDown();
907 TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate_NoParent) {
908 base::ScopedTempDir temp_dir;
909 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
911 CannedSyncableFileSystem file_system(GURL(kOrigin1),
912 in_memory_env_.get(),
913 io_task_runner_.get(),
914 file_task_runner_.get());
915 file_system.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED);
917 sync_context_ = new LocalFileSyncContext(
918 dir_.path(), in_memory_env_.get(),
919 ui_task_runner_.get(), io_task_runner_.get());
920 ASSERT_EQ(SYNC_STATUS_OK,
921 file_system.MaybeInitializeFileSystemContext(sync_context_.get()));
922 ASSERT_EQ(base::File::FILE_OK, file_system.OpenFileSystem());
924 const char kTestFileData[] = "Lorem ipsum!";
925 const FileSystemURL kDir(file_system.URL("dir"));
926 const FileSystemURL kFile(file_system.URL("dir/file"));
928 // Either kDir or kFile not exist yet.
929 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file_system.FileExists(kDir));
930 EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file_system.FileExists(kFile));
932 // Prepare a temporary file which represents remote file data.
933 const base::FilePath kFilePath(temp_dir.path().Append(FPL("file")));
934 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData) - 1),
935 base::WriteFile(kFilePath, kTestFileData,
936 arraysize(kTestFileData) - 1));
938 // Calling ApplyChange's with kFilePath should create
939 // kFile along with kDir.
940 FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE,
941 SYNC_FILE_TYPE_FILE);
942 EXPECT_EQ(SYNC_STATUS_OK,
943 ApplyRemoteChange(file_system.file_system_context(),
944 change, kFilePath, kFile,
945 SYNC_FILE_TYPE_UNKNOWN));
947 // The changes applied by ApplyRemoteChange should not be recorded in
948 // the change tracker.
949 FileSystemURLSet urls;
950 urls.clear();
951 file_system.GetChangedURLsInTracker(&urls);
952 EXPECT_TRUE(urls.empty());
954 // Make sure kDir and kFile are created by ApplyRemoteChange.
955 EXPECT_EQ(base::File::FILE_OK, file_system.FileExists(kFile));
956 EXPECT_EQ(base::File::FILE_OK, file_system.DirectoryExists(kDir));
958 sync_context_->ShutdownOnUIThread();
959 file_system.TearDown();
962 } // namespace sync_file_system