local_file_sync_context_unittest.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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. 4 5#include "chrome/browser/sync_file_system/local/local_file_sync_context.h" 6 7#include <vector> 8 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/file_util.h" 12#include "base/files/file_path.h" 13#include "base/message_loop/message_loop.h" 14#include "base/platform_file.h" 15#include "base/stl_util.h" 16#include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h" 17#include "chrome/browser/sync_file_system/local/local_file_change_tracker.h" 18#include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" 19#include "chrome/browser/sync_file_system/sync_file_metadata.h" 20#include "chrome/browser/sync_file_system/sync_status_code.h" 21#include "chrome/browser/sync_file_system/syncable_file_system_util.h" 22#include "content/public/browser/browser_thread.h" 23#include "content/public/test/test_browser_thread_bundle.h" 24#include "testing/gtest/include/gtest/gtest.h" 25#include "webkit/browser/blob/mock_blob_url_request_context.h" 26#include "webkit/browser/fileapi/file_system_context.h" 27#include "webkit/browser/fileapi/file_system_operation_runner.h" 28#include "webkit/browser/fileapi/isolated_context.h" 29#include "webkit/common/blob/scoped_file.h" 30 31#define FPL FILE_PATH_LITERAL 32 33using content::BrowserThread; 34using fileapi::FileSystemContext; 35using fileapi::FileSystemURL; 36using fileapi::FileSystemURLSet; 37 38// This tests LocalFileSyncContext behavior in multi-thread / 39// multi-file-system-context environment. 40// Basic combined tests (single-thread / single-file-system-context) 41// that involve LocalFileSyncContext are also in 42// syncable_file_system_unittests.cc. 43 44namespace sync_file_system { 45 46namespace { 47const char kOrigin1[] = "http://example.com"; 48const char kOrigin2[] = "http://chromium.org"; 49} 50 51class LocalFileSyncContextTest : public testing::Test { 52 protected: 53 LocalFileSyncContextTest() 54 : thread_bundle_( 55 content::TestBrowserThreadBundle::REAL_FILE_THREAD | 56 content::TestBrowserThreadBundle::REAL_IO_THREAD), 57 status_(SYNC_FILE_ERROR_FAILED), 58 file_error_(base::PLATFORM_FILE_ERROR_FAILED), 59 async_modify_finished_(false), 60 has_inflight_prepare_for_sync_(false) {} 61 62 virtual void SetUp() OVERRIDE { 63 RegisterSyncableFileSystem(); 64 ASSERT_TRUE(dir_.CreateUniqueTempDir()); 65 66 ui_task_runner_ = base::MessageLoop::current()->message_loop_proxy(); 67 io_task_runner_ = BrowserThread::GetMessageLoopProxyForThread( 68 BrowserThread::IO); 69 file_task_runner_ = BrowserThread::GetMessageLoopProxyForThread( 70 BrowserThread::IO); 71 } 72 73 virtual void TearDown() OVERRIDE { 74 RevokeSyncableFileSystem(); 75 } 76 77 void StartPrepareForSync(FileSystemContext* file_system_context, 78 const FileSystemURL& url, 79 LocalFileSyncContext::SyncMode sync_mode, 80 SyncFileMetadata* metadata, 81 FileChangeList* changes, 82 webkit_blob::ScopedFile* snapshot) { 83 ASSERT_TRUE(changes != NULL); 84 ASSERT_FALSE(has_inflight_prepare_for_sync_); 85 status_ = SYNC_STATUS_UNKNOWN; 86 has_inflight_prepare_for_sync_ = true; 87 sync_context_->PrepareForSync( 88 file_system_context, 89 url, 90 sync_mode, 91 base::Bind(&LocalFileSyncContextTest::DidPrepareForSync, 92 base::Unretained(this), metadata, changes, snapshot)); 93 } 94 95 SyncStatusCode PrepareForSync(FileSystemContext* file_system_context, 96 const FileSystemURL& url, 97 LocalFileSyncContext::SyncMode sync_mode, 98 SyncFileMetadata* metadata, 99 FileChangeList* changes, 100 webkit_blob::ScopedFile* snapshot) { 101 StartPrepareForSync(file_system_context, url, sync_mode, 102 metadata, changes, snapshot); 103 base::MessageLoop::current()->Run(); 104 return status_; 105 } 106 107 base::Closure GetPrepareForSyncClosure( 108 FileSystemContext* file_system_context, 109 const FileSystemURL& url, 110 LocalFileSyncContext::SyncMode sync_mode, 111 SyncFileMetadata* metadata, 112 FileChangeList* changes, 113 webkit_blob::ScopedFile* snapshot) { 114 return base::Bind(&LocalFileSyncContextTest::StartPrepareForSync, 115 base::Unretained(this), 116 base::Unretained(file_system_context), 117 url, sync_mode, metadata, changes, snapshot); 118 } 119 120 void DidPrepareForSync(SyncFileMetadata* metadata_out, 121 FileChangeList* changes_out, 122 webkit_blob::ScopedFile* snapshot_out, 123 SyncStatusCode status, 124 const LocalFileSyncInfo& sync_file_info, 125 scoped_ptr<webkit_blob::ScopedFile> snapshot) { 126 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); 127 has_inflight_prepare_for_sync_ = false; 128 status_ = status; 129 *metadata_out = sync_file_info.metadata; 130 *changes_out = sync_file_info.changes; 131 if (snapshot_out && snapshot) 132 *snapshot_out = snapshot->Pass(); 133 base::MessageLoop::current()->Quit(); 134 } 135 136 SyncStatusCode ApplyRemoteChange(FileSystemContext* file_system_context, 137 const FileChange& change, 138 const base::FilePath& local_path, 139 const FileSystemURL& url, 140 SyncFileType expected_file_type) { 141 SCOPED_TRACE(testing::Message() << "ApplyChange for " << 142 url.DebugString()); 143 144 // First we should call PrepareForSync to disable writing. 145 SyncFileMetadata metadata; 146 FileChangeList changes; 147 EXPECT_EQ(SYNC_STATUS_OK, 148 PrepareForSync(file_system_context, url, 149 LocalFileSyncContext::SYNC_EXCLUSIVE, 150 &metadata, &changes, NULL)); 151 EXPECT_EQ(expected_file_type, metadata.file_type); 152 153 status_ = SYNC_STATUS_UNKNOWN; 154 sync_context_->ApplyRemoteChange( 155 file_system_context, change, local_path, url, 156 base::Bind(&LocalFileSyncContextTest::DidApplyRemoteChange, 157 base::Unretained(this))); 158 base::MessageLoop::current()->Run(); 159 return status_; 160 } 161 162 void DidApplyRemoteChange(SyncStatusCode status) { 163 base::MessageLoop::current()->Quit(); 164 status_ = status; 165 } 166 167 void StartModifyFileOnIOThread(CannedSyncableFileSystem* file_system, 168 const FileSystemURL& url) { 169 ASSERT_TRUE(file_system != NULL); 170 if (!io_task_runner_->RunsTasksOnCurrentThread()) { 171 async_modify_finished_ = false; 172 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); 173 io_task_runner_->PostTask( 174 FROM_HERE, 175 base::Bind(&LocalFileSyncContextTest::StartModifyFileOnIOThread, 176 base::Unretained(this), file_system, url)); 177 return; 178 } 179 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread()); 180 file_error_ = base::PLATFORM_FILE_ERROR_FAILED; 181 file_system->operation_runner()->Truncate( 182 url, 1, base::Bind(&LocalFileSyncContextTest::DidModifyFile, 183 base::Unretained(this))); 184 } 185 186 base::PlatformFileError WaitUntilModifyFileIsDone() { 187 while (!async_modify_finished_) 188 base::MessageLoop::current()->RunUntilIdle(); 189 return file_error_; 190 } 191 192 void DidModifyFile(base::PlatformFileError error) { 193 if (!ui_task_runner_->RunsTasksOnCurrentThread()) { 194 ASSERT_TRUE(io_task_runner_->RunsTasksOnCurrentThread()); 195 ui_task_runner_->PostTask( 196 FROM_HERE, 197 base::Bind(&LocalFileSyncContextTest::DidModifyFile, 198 base::Unretained(this), error)); 199 return; 200 } 201 ASSERT_TRUE(ui_task_runner_->RunsTasksOnCurrentThread()); 202 file_error_ = error; 203 async_modify_finished_ = true; 204 } 205 206 void SimulateFinishSync(FileSystemContext* file_system_context, 207 const FileSystemURL& url, 208 SyncStatusCode status) { 209 sync_context_->CommitChangeStatusForURL( 210 file_system_context, 211 url, 212 status, 213 base::Bind(&LocalFileSyncContext::ClearSyncFlagForURL, 214 sync_context_, url)); 215 base::MessageLoop::current()->RunUntilIdle(); 216 } 217 218 void PrepareForSync_Basic(LocalFileSyncContext::SyncMode sync_mode, 219 SyncStatusCode simulate_sync_finish_status) { 220 CannedSyncableFileSystem file_system(GURL(kOrigin1), 221 io_task_runner_.get(), 222 file_task_runner_.get()); 223 file_system.SetUp(); 224 sync_context_ = new LocalFileSyncContext( 225 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 226 ASSERT_EQ(SYNC_STATUS_OK, 227 file_system.MaybeInitializeFileSystemContext( 228 sync_context_.get())); 229 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 230 231 const FileSystemURL kFile(file_system.URL("file")); 232 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile)); 233 234 SyncFileMetadata metadata; 235 FileChangeList changes; 236 EXPECT_EQ(SYNC_STATUS_OK, 237 PrepareForSync(file_system.file_system_context(), kFile, 238 sync_mode, &metadata, &changes, NULL)); 239 EXPECT_EQ(1U, changes.size()); 240 EXPECT_TRUE(changes.list().back().IsFile()); 241 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 242 243 // We should see the same set of changes. 244 file_system.GetChangesForURLInTracker(kFile, &changes); 245 EXPECT_EQ(1U, changes.size()); 246 EXPECT_TRUE(changes.list().back().IsFile()); 247 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 248 249 SimulateFinishSync(file_system.file_system_context(), kFile, 250 simulate_sync_finish_status); 251 252 file_system.GetChangesForURLInTracker(kFile, &changes); 253 if (simulate_sync_finish_status == SYNC_STATUS_OK) { 254 // The change's cleared. 255 EXPECT_TRUE(changes.empty()); 256 } else { 257 EXPECT_EQ(1U, changes.size()); 258 EXPECT_TRUE(changes.list().back().IsFile()); 259 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 260 } 261 262 sync_context_->ShutdownOnUIThread(); 263 sync_context_ = NULL; 264 265 file_system.TearDown(); 266 } 267 268 void PrepareForSync_WriteDuringSync( 269 LocalFileSyncContext::SyncMode sync_mode) { 270 CannedSyncableFileSystem file_system(GURL(kOrigin1), 271 io_task_runner_.get(), 272 file_task_runner_.get()); 273 file_system.SetUp(); 274 sync_context_ = new LocalFileSyncContext( 275 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 276 ASSERT_EQ(SYNC_STATUS_OK, 277 file_system.MaybeInitializeFileSystemContext( 278 sync_context_.get())); 279 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 280 281 const FileSystemURL kFile(file_system.URL("file")); 282 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile)); 283 284 SyncFileMetadata metadata; 285 FileChangeList changes; 286 webkit_blob::ScopedFile snapshot; 287 EXPECT_EQ(SYNC_STATUS_OK, 288 PrepareForSync(file_system.file_system_context(), kFile, 289 sync_mode, &metadata, &changes, &snapshot)); 290 EXPECT_EQ(1U, changes.size()); 291 EXPECT_TRUE(changes.list().back().IsFile()); 292 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 293 294 EXPECT_EQ(sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT, 295 !snapshot.path().empty()); 296 297 // Tracker keeps same set of changes. 298 file_system.GetChangesForURLInTracker(kFile, &changes); 299 EXPECT_EQ(1U, changes.size()); 300 EXPECT_TRUE(changes.list().back().IsFile()); 301 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 302 303 StartModifyFileOnIOThread(&file_system, kFile); 304 305 if (sync_mode == LocalFileSyncContext::SYNC_SNAPSHOT) { 306 // Write should succeed. 307 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); 308 } else { 309 base::MessageLoop::current()->RunUntilIdle(); 310 EXPECT_FALSE(async_modify_finished_); 311 } 312 313 SimulateFinishSync(file_system.file_system_context(), kFile, 314 SYNC_STATUS_OK); 315 316 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); 317 318 // Sync succeeded, but the other change that was made during or 319 // after sync is recorded. 320 file_system.GetChangesForURLInTracker(kFile, &changes); 321 EXPECT_EQ(1U, changes.size()); 322 EXPECT_TRUE(changes.list().back().IsFile()); 323 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 324 325 sync_context_->ShutdownOnUIThread(); 326 sync_context_ = NULL; 327 328 file_system.TearDown(); 329 } 330 331 ScopedEnableSyncFSDirectoryOperation enable_directory_operation_; 332 333 base::ScopedTempDir dir_; 334 335 // These need to remain until the very end. 336 content::TestBrowserThreadBundle thread_bundle_; 337 338 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; 339 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; 340 scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; 341 342 scoped_refptr<LocalFileSyncContext> sync_context_; 343 344 SyncStatusCode status_; 345 base::PlatformFileError file_error_; 346 bool async_modify_finished_; 347 bool has_inflight_prepare_for_sync_; 348}; 349 350TEST_F(LocalFileSyncContextTest, ConstructAndDestruct) { 351 sync_context_ = 352 new LocalFileSyncContext( 353 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 354 sync_context_->ShutdownOnUIThread(); 355} 356 357TEST_F(LocalFileSyncContextTest, InitializeFileSystemContext) { 358 CannedSyncableFileSystem file_system(GURL(kOrigin1), 359 io_task_runner_.get(), 360 file_task_runner_.get()); 361 file_system.SetUp(); 362 363 sync_context_ = new LocalFileSyncContext( 364 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 365 366 // Initializes file_system using |sync_context_|. 367 EXPECT_EQ(SYNC_STATUS_OK, 368 file_system.MaybeInitializeFileSystemContext(sync_context_.get())); 369 370 // Make sure everything's set up for file_system to be able to handle 371 // syncable file system operations. 372 EXPECT_TRUE(file_system.backend()->sync_context() != NULL); 373 EXPECT_TRUE(file_system.backend()->change_tracker() != NULL); 374 EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context()); 375 376 // Calling MaybeInitialize for the same context multiple times must be ok. 377 EXPECT_EQ(SYNC_STATUS_OK, 378 file_system.MaybeInitializeFileSystemContext(sync_context_.get())); 379 EXPECT_EQ(sync_context_.get(), file_system.backend()->sync_context()); 380 381 // Opens the file_system, perform some operation and see if the change tracker 382 // correctly captures the change. 383 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 384 385 const FileSystemURL kURL(file_system.URL("foo")); 386 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kURL)); 387 388 FileSystemURLSet urls; 389 file_system.GetChangedURLsInTracker(&urls); 390 ASSERT_EQ(1U, urls.size()); 391 EXPECT_TRUE(ContainsKey(urls, kURL)); 392 393 // Finishing the test. 394 sync_context_->ShutdownOnUIThread(); 395 file_system.TearDown(); 396} 397 398TEST_F(LocalFileSyncContextTest, MultipleFileSystemContexts) { 399 CannedSyncableFileSystem file_system1(GURL(kOrigin1), 400 io_task_runner_.get(), 401 file_task_runner_.get()); 402 CannedSyncableFileSystem file_system2(GURL(kOrigin2), 403 io_task_runner_.get(), 404 file_task_runner_.get()); 405 file_system1.SetUp(); 406 file_system2.SetUp(); 407 408 sync_context_ = new LocalFileSyncContext( 409 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 410 411 // Initializes file_system1 and file_system2. 412 EXPECT_EQ(SYNC_STATUS_OK, 413 file_system1.MaybeInitializeFileSystemContext(sync_context_.get())); 414 EXPECT_EQ(SYNC_STATUS_OK, 415 file_system2.MaybeInitializeFileSystemContext(sync_context_.get())); 416 417 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system1.OpenFileSystem()); 418 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system2.OpenFileSystem()); 419 420 const FileSystemURL kURL1(file_system1.URL("foo")); 421 const FileSystemURL kURL2(file_system2.URL("bar")); 422 423 // Creates a file in file_system1. 424 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system1.CreateFile(kURL1)); 425 426 // file_system1's tracker must have recorded the change. 427 FileSystemURLSet urls; 428 file_system1.GetChangedURLsInTracker(&urls); 429 ASSERT_EQ(1U, urls.size()); 430 EXPECT_TRUE(ContainsKey(urls, kURL1)); 431 432 // file_system1's tracker must have no change. 433 urls.clear(); 434 file_system2.GetChangedURLsInTracker(&urls); 435 ASSERT_TRUE(urls.empty()); 436 437 // Creates a directory in file_system2. 438 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system2.CreateDirectory(kURL2)); 439 440 // file_system1's tracker must have the change for kURL1 as before. 441 urls.clear(); 442 file_system1.GetChangedURLsInTracker(&urls); 443 ASSERT_EQ(1U, urls.size()); 444 EXPECT_TRUE(ContainsKey(urls, kURL1)); 445 446 // file_system2's tracker now must have the change for kURL2. 447 urls.clear(); 448 file_system2.GetChangedURLsInTracker(&urls); 449 ASSERT_EQ(1U, urls.size()); 450 EXPECT_TRUE(ContainsKey(urls, kURL2)); 451 452 SyncFileMetadata metadata; 453 FileChangeList changes; 454 EXPECT_EQ(SYNC_STATUS_OK, 455 PrepareForSync(file_system1.file_system_context(), kURL1, 456 LocalFileSyncContext::SYNC_EXCLUSIVE, 457 &metadata, &changes, NULL)); 458 EXPECT_EQ(1U, changes.size()); 459 EXPECT_TRUE(changes.list().back().IsFile()); 460 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 461 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type); 462 EXPECT_EQ(0, metadata.size); 463 464 changes.clear(); 465 EXPECT_EQ(SYNC_STATUS_OK, 466 PrepareForSync(file_system2.file_system_context(), kURL2, 467 LocalFileSyncContext::SYNC_EXCLUSIVE, 468 &metadata, &changes, NULL)); 469 EXPECT_EQ(1U, changes.size()); 470 EXPECT_FALSE(changes.list().back().IsFile()); 471 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 472 EXPECT_EQ(SYNC_FILE_TYPE_DIRECTORY, metadata.file_type); 473 EXPECT_EQ(0, metadata.size); 474 475 sync_context_->ShutdownOnUIThread(); 476 sync_context_ = NULL; 477 478 file_system1.TearDown(); 479 file_system2.TearDown(); 480} 481 482TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Exclusive) { 483 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE, 484 SYNC_STATUS_OK); 485} 486 487TEST_F(LocalFileSyncContextTest, PrepareSync_SyncSuccess_Snapshot) { 488 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT, 489 SYNC_STATUS_OK); 490} 491 492TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Exclusive) { 493 PrepareForSync_Basic(LocalFileSyncContext::SYNC_EXCLUSIVE, 494 SYNC_STATUS_FAILED); 495} 496 497TEST_F(LocalFileSyncContextTest, PrepareSync_SyncFailure_Snapshot) { 498 PrepareForSync_Basic(LocalFileSyncContext::SYNC_SNAPSHOT, 499 SYNC_STATUS_FAILED); 500} 501 502TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Exclusive) { 503 PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_EXCLUSIVE); 504} 505 506TEST_F(LocalFileSyncContextTest, PrepareSync_WriteDuringSync_Snapshot) { 507 PrepareForSync_WriteDuringSync(LocalFileSyncContext::SYNC_SNAPSHOT); 508} 509 510// LocalFileSyncContextTest.PrepareSyncWhileWriting is flaky on android. 511// http://crbug.com/239793 512#if defined(OS_ANDROID) 513#define MAYBE_PrepareSyncWhileWriting DISABLED_PrepareSyncWhileWriting 514#else 515#define MAYBE_PrepareSyncWhileWriting PrepareSyncWhileWriting 516#endif 517TEST_F(LocalFileSyncContextTest, MAYBE_PrepareSyncWhileWriting) { 518 CannedSyncableFileSystem file_system(GURL(kOrigin1), 519 io_task_runner_.get(), 520 file_task_runner_.get()); 521 file_system.SetUp(); 522 sync_context_ = new LocalFileSyncContext( 523 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 524 EXPECT_EQ(SYNC_STATUS_OK, 525 file_system.MaybeInitializeFileSystemContext(sync_context_.get())); 526 527 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 528 529 const FileSystemURL kURL1(file_system.URL("foo")); 530 531 // Creates a file in file_system. 532 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kURL1)); 533 534 // Kick file write on IO thread. 535 StartModifyFileOnIOThread(&file_system, kURL1); 536 537 // Until the operation finishes PrepareForSync should return BUSY error. 538 SyncFileMetadata metadata; 539 metadata.file_type = SYNC_FILE_TYPE_UNKNOWN; 540 FileChangeList changes; 541 EXPECT_EQ(SYNC_STATUS_FILE_BUSY, 542 PrepareForSync(file_system.file_system_context(), kURL1, 543 LocalFileSyncContext::SYNC_EXCLUSIVE, 544 &metadata, &changes, NULL)); 545 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type); 546 547 // Register PrepareForSync method to be invoked when kURL1 becomes 548 // syncable. (Actually this may be done after all operations are done 549 // on IO thread in this test.) 550 metadata.file_type = SYNC_FILE_TYPE_UNKNOWN; 551 changes.clear(); 552 sync_context_->RegisterURLForWaitingSync( 553 kURL1, GetPrepareForSyncClosure(file_system.file_system_context(), kURL1, 554 LocalFileSyncContext::SYNC_EXCLUSIVE, 555 &metadata, &changes, NULL)); 556 557 // Wait for the completion. 558 EXPECT_EQ(base::PLATFORM_FILE_OK, WaitUntilModifyFileIsDone()); 559 560 // The PrepareForSync must have been started; wait until DidPrepareForSync 561 // is done. 562 base::MessageLoop::current()->Run(); 563 ASSERT_FALSE(has_inflight_prepare_for_sync_); 564 565 // Now PrepareForSync should have run and returned OK. 566 EXPECT_EQ(SYNC_STATUS_OK, status_); 567 EXPECT_EQ(1U, changes.size()); 568 EXPECT_TRUE(changes.list().back().IsFile()); 569 EXPECT_TRUE(changes.list().back().IsAddOrUpdate()); 570 EXPECT_EQ(SYNC_FILE_TYPE_FILE, metadata.file_type); 571 EXPECT_EQ(1, metadata.size); 572 573 sync_context_->ShutdownOnUIThread(); 574 sync_context_ = NULL; 575 file_system.TearDown(); 576} 577 578TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForDeletion) { 579 CannedSyncableFileSystem file_system(GURL(kOrigin1), 580 io_task_runner_.get(), 581 file_task_runner_.get()); 582 file_system.SetUp(); 583 584 sync_context_ = new LocalFileSyncContext( 585 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 586 ASSERT_EQ(SYNC_STATUS_OK, 587 file_system.MaybeInitializeFileSystemContext(sync_context_.get())); 588 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 589 590 // Record the initial usage (likely 0). 591 int64 initial_usage = -1; 592 int64 quota = -1; 593 EXPECT_EQ(quota::kQuotaStatusOk, 594 file_system.GetUsageAndQuota(&initial_usage, "a)); 595 596 // Create a file and directory in the file_system. 597 const FileSystemURL kFile(file_system.URL("file")); 598 const FileSystemURL kDir(file_system.URL("dir")); 599 const FileSystemURL kChild(file_system.URL("dir/child")); 600 601 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile)); 602 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateDirectory(kDir)); 603 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kChild)); 604 605 // file_system's change tracker must have recorded the creation. 606 FileSystemURLSet urls; 607 file_system.GetChangedURLsInTracker(&urls); 608 ASSERT_EQ(3U, urls.size()); 609 ASSERT_TRUE(ContainsKey(urls, kFile)); 610 ASSERT_TRUE(ContainsKey(urls, kDir)); 611 ASSERT_TRUE(ContainsKey(urls, kChild)); 612 for (FileSystemURLSet::iterator iter = urls.begin(); 613 iter != urls.end(); ++iter) { 614 file_system.ClearChangeForURLInTracker(*iter); 615 } 616 617 // At this point the usage must be greater than the initial usage. 618 int64 new_usage = -1; 619 EXPECT_EQ(quota::kQuotaStatusOk, 620 file_system.GetUsageAndQuota(&new_usage, "a)); 621 EXPECT_GT(new_usage, initial_usage); 622 623 // Now let's apply remote deletion changes. 624 FileChange change(FileChange::FILE_CHANGE_DELETE, 625 SYNC_FILE_TYPE_FILE); 626 EXPECT_EQ(SYNC_STATUS_OK, 627 ApplyRemoteChange(file_system.file_system_context(), 628 change, base::FilePath(), kFile, 629 SYNC_FILE_TYPE_FILE)); 630 631 // The implementation doesn't check file type for deletion, and it must be ok 632 // even if we don't know if the deletion change was for a file or a directory. 633 change = FileChange(FileChange::FILE_CHANGE_DELETE, 634 SYNC_FILE_TYPE_UNKNOWN); 635 EXPECT_EQ(SYNC_STATUS_OK, 636 ApplyRemoteChange(file_system.file_system_context(), 637 change, base::FilePath(), kDir, 638 SYNC_FILE_TYPE_DIRECTORY)); 639 640 // Check the directory/files are deleted successfully. 641 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, 642 file_system.FileExists(kFile)); 643 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, 644 file_system.DirectoryExists(kDir)); 645 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, 646 file_system.FileExists(kChild)); 647 648 // The changes applied by ApplyRemoteChange should not be recorded in 649 // the change tracker. 650 urls.clear(); 651 file_system.GetChangedURLsInTracker(&urls); 652 EXPECT_TRUE(urls.empty()); 653 654 // The quota usage data must have reflected the deletion. 655 EXPECT_EQ(quota::kQuotaStatusOk, 656 file_system.GetUsageAndQuota(&new_usage, "a)); 657 EXPECT_EQ(new_usage, initial_usage); 658 659 sync_context_->ShutdownOnUIThread(); 660 sync_context_ = NULL; 661 file_system.TearDown(); 662} 663 664TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate) { 665 base::ScopedTempDir temp_dir; 666 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 667 668 CannedSyncableFileSystem file_system(GURL(kOrigin1), 669 io_task_runner_.get(), 670 file_task_runner_.get()); 671 file_system.SetUp(); 672 673 sync_context_ = new LocalFileSyncContext( 674 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 675 ASSERT_EQ(SYNC_STATUS_OK, 676 file_system.MaybeInitializeFileSystemContext(sync_context_.get())); 677 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 678 679 const FileSystemURL kFile1(file_system.URL("file1")); 680 const FileSystemURL kFile2(file_system.URL("file2")); 681 const FileSystemURL kDir(file_system.URL("dir")); 682 683 const char kTestFileData0[] = "0123456789"; 684 const char kTestFileData1[] = "Lorem ipsum!"; 685 const char kTestFileData2[] = "This is sample test data."; 686 687 // Create kFile1 and populate it with kTestFileData0. 688 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.CreateFile(kFile1)); 689 EXPECT_EQ(static_cast<int64>(arraysize(kTestFileData0) - 1), 690 file_system.WriteString(kFile1, kTestFileData0)); 691 692 // kFile2 and kDir are not there yet. 693 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, 694 file_system.FileExists(kFile2)); 695 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, 696 file_system.DirectoryExists(kDir)); 697 698 // file_system's change tracker must have recorded the creation. 699 FileSystemURLSet urls; 700 file_system.GetChangedURLsInTracker(&urls); 701 ASSERT_EQ(1U, urls.size()); 702 EXPECT_TRUE(ContainsKey(urls, kFile1)); 703 file_system.ClearChangeForURLInTracker(*urls.begin()); 704 705 // Prepare temporary files which represent the remote file data. 706 const base::FilePath kFilePath1(temp_dir.path().Append(FPL("file1"))); 707 const base::FilePath kFilePath2(temp_dir.path().Append(FPL("file2"))); 708 709 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData1) - 1), 710 file_util::WriteFile(kFilePath1, kTestFileData1, 711 arraysize(kTestFileData1) - 1)); 712 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData2) - 1), 713 file_util::WriteFile(kFilePath2, kTestFileData2, 714 arraysize(kTestFileData2) - 1)); 715 716 // Record the usage. 717 int64 usage = -1, new_usage = -1; 718 int64 quota = -1; 719 EXPECT_EQ(quota::kQuotaStatusOk, 720 file_system.GetUsageAndQuota(&usage, "a)); 721 722 // Here in the local filesystem we have: 723 // * kFile1 with kTestFileData0 724 // 725 // In the remote side let's assume we have: 726 // * kFile1 with kTestFileData1 727 // * kFile2 with kTestFileData2 728 // * kDir 729 // 730 // By calling ApplyChange's: 731 // * kFile1 will be updated to have kTestFileData1 732 // * kFile2 will be created 733 // * kDir will be created 734 735 // Apply the remote change to kFile1 (which will update the file). 736 FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 737 SYNC_FILE_TYPE_FILE); 738 EXPECT_EQ(SYNC_STATUS_OK, 739 ApplyRemoteChange(file_system.file_system_context(), 740 change, kFilePath1, kFile1, 741 SYNC_FILE_TYPE_FILE)); 742 743 // Check if the usage has been increased by (kTestFileData1 - kTestFileData0). 744 const int updated_size = 745 arraysize(kTestFileData1) - arraysize(kTestFileData0); 746 EXPECT_EQ(quota::kQuotaStatusOk, 747 file_system.GetUsageAndQuota(&new_usage, "a)); 748 EXPECT_EQ(updated_size, new_usage - usage); 749 750 // Apply remote changes to kFile2 and kDir (should create a file and 751 // directory respectively). 752 // They are non-existent yet so their expected file type (the last 753 // parameter of ApplyRemoteChange) are 754 // SYNC_FILE_TYPE_UNKNOWN. 755 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 756 SYNC_FILE_TYPE_FILE); 757 EXPECT_EQ(SYNC_STATUS_OK, 758 ApplyRemoteChange(file_system.file_system_context(), 759 change, kFilePath2, kFile2, 760 SYNC_FILE_TYPE_UNKNOWN)); 761 762 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 763 SYNC_FILE_TYPE_DIRECTORY); 764 EXPECT_EQ(SYNC_STATUS_OK, 765 ApplyRemoteChange(file_system.file_system_context(), 766 change, base::FilePath(), kDir, 767 SYNC_FILE_TYPE_UNKNOWN)); 768 769 // Calling ApplyRemoteChange with different file type should be handled as 770 // overwrite. 771 change = 772 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, SYNC_FILE_TYPE_FILE); 773 EXPECT_EQ(SYNC_STATUS_OK, 774 ApplyRemoteChange(file_system.file_system_context(), 775 change, 776 kFilePath1, 777 kDir, 778 SYNC_FILE_TYPE_DIRECTORY)); 779 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kDir)); 780 781 change = FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 782 SYNC_FILE_TYPE_DIRECTORY); 783 EXPECT_EQ(SYNC_STATUS_OK, 784 ApplyRemoteChange(file_system.file_system_context(), 785 change, 786 kFilePath1, 787 kDir, 788 SYNC_FILE_TYPE_FILE)); 789 790 // Creating a file/directory must have increased the usage more than 791 // the size of kTestFileData2. 792 new_usage = usage; 793 EXPECT_EQ(quota::kQuotaStatusOk, 794 file_system.GetUsageAndQuota(&new_usage, "a)); 795 EXPECT_GT(new_usage, 796 static_cast<int64>(usage + arraysize(kTestFileData2) - 1)); 797 798 // The changes applied by ApplyRemoteChange should not be recorded in 799 // the change tracker. 800 urls.clear(); 801 file_system.GetChangedURLsInTracker(&urls); 802 EXPECT_TRUE(urls.empty()); 803 804 // Make sure all three files/directory exist. 805 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile1)); 806 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile2)); 807 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.DirectoryExists(kDir)); 808 809 sync_context_->ShutdownOnUIThread(); 810 file_system.TearDown(); 811} 812 813TEST_F(LocalFileSyncContextTest, ApplyRemoteChangeForAddOrUpdate_NoParent) { 814 base::ScopedTempDir temp_dir; 815 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 816 817 CannedSyncableFileSystem file_system(GURL(kOrigin1), 818 io_task_runner_.get(), 819 file_task_runner_.get()); 820 file_system.SetUp(); 821 822 sync_context_ = new LocalFileSyncContext( 823 dir_.path(), ui_task_runner_.get(), io_task_runner_.get()); 824 ASSERT_EQ(SYNC_STATUS_OK, 825 file_system.MaybeInitializeFileSystemContext(sync_context_.get())); 826 ASSERT_EQ(base::PLATFORM_FILE_OK, file_system.OpenFileSystem()); 827 828 const char kTestFileData[] = "Lorem ipsum!"; 829 const FileSystemURL kDir(file_system.URL("dir")); 830 const FileSystemURL kFile(file_system.URL("dir/file")); 831 832 // Either kDir or kFile not exist yet. 833 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_system.FileExists(kDir)); 834 EXPECT_EQ(base::PLATFORM_FILE_ERROR_NOT_FOUND, file_system.FileExists(kFile)); 835 836 // Prepare a temporary file which represents remote file data. 837 const base::FilePath kFilePath(temp_dir.path().Append(FPL("file"))); 838 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData) - 1), 839 file_util::WriteFile(kFilePath, kTestFileData, 840 arraysize(kTestFileData) - 1)); 841 842 // Calling ApplyChange's with kFilePath should create 843 // kFile along with kDir. 844 FileChange change(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 845 SYNC_FILE_TYPE_FILE); 846 EXPECT_EQ(SYNC_STATUS_OK, 847 ApplyRemoteChange(file_system.file_system_context(), 848 change, kFilePath, kFile, 849 SYNC_FILE_TYPE_UNKNOWN)); 850 851 // The changes applied by ApplyRemoteChange should not be recorded in 852 // the change tracker. 853 FileSystemURLSet urls; 854 urls.clear(); 855 file_system.GetChangedURLsInTracker(&urls); 856 EXPECT_TRUE(urls.empty()); 857 858 // Make sure kDir and kFile are created by ApplyRemoteChange. 859 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.FileExists(kFile)); 860 EXPECT_EQ(base::PLATFORM_FILE_OK, file_system.DirectoryExists(kDir)); 861 862 sync_context_->ShutdownOnUIThread(); 863 file_system.TearDown(); 864} 865 866} // namespace sync_file_system 867