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_change_tracker.h" 6 7 #include <deque> 8 #include <set> 9 10 #include "base/basictypes.h" 11 #include "base/files/scoped_temp_dir.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/message_loop/message_loop.h" 14 #include "base/stl_util.h" 15 #include "base/thread_task_runner_handle.h" 16 #include "chrome/browser/sync_file_system/local/canned_syncable_file_system.h" 17 #include "chrome/browser/sync_file_system/local/local_file_sync_context.h" 18 #include "chrome/browser/sync_file_system/local/sync_file_system_backend.h" 19 #include "chrome/browser/sync_file_system/sync_status_code.h" 20 #include "chrome/browser/sync_file_system/syncable_file_system_util.h" 21 #include "content/public/test/mock_blob_url_request_context.h" 22 #include "storage/browser/fileapi/file_system_context.h" 23 #include "storage/browser/quota/quota_manager.h" 24 #include "testing/gtest/include/gtest/gtest.h" 25 #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" 26 #include "third_party/leveldatabase/src/include/leveldb/env.h" 27 28 using storage::FileSystemContext; 29 using storage::FileSystemURL; 30 using storage::FileSystemURLSet; 31 using content::MockBlobURLRequestContext; 32 using content::ScopedTextBlob; 33 34 namespace sync_file_system { 35 36 class LocalFileChangeTrackerTest : public testing::Test { 37 public: 38 LocalFileChangeTrackerTest() 39 : in_memory_env_(leveldb::NewMemEnv(leveldb::Env::Default())), 40 file_system_(GURL("http://example.com"), 41 in_memory_env_.get(), 42 base::ThreadTaskRunnerHandle::Get().get(), 43 base::ThreadTaskRunnerHandle::Get().get()) {} 44 45 virtual void SetUp() OVERRIDE { 46 file_system_.SetUp(CannedSyncableFileSystem::QUOTA_ENABLED); 47 48 ASSERT_TRUE(base_dir_.CreateUniqueTempDir()); 49 sync_context_ = 50 new LocalFileSyncContext(base_dir_.path(), 51 in_memory_env_.get(), 52 base::ThreadTaskRunnerHandle::Get().get(), 53 base::ThreadTaskRunnerHandle::Get().get()); 54 ASSERT_EQ( 55 sync_file_system::SYNC_STATUS_OK, 56 file_system_.MaybeInitializeFileSystemContext(sync_context_.get())); 57 } 58 59 virtual void TearDown() OVERRIDE { 60 if (sync_context_.get()) 61 sync_context_->ShutdownOnUIThread(); 62 sync_context_ = NULL; 63 64 message_loop_.RunUntilIdle(); 65 file_system_.TearDown(); 66 // Make sure we don't leave the external filesystem. 67 // (CannedSyncableFileSystem::TearDown does not do this as there may be 68 // multiple syncable file systems registered for the name) 69 RevokeSyncableFileSystem(); 70 } 71 72 protected: 73 FileSystemURL URL(const std::string& path) { 74 return file_system_.URL(path); 75 } 76 77 FileSystemContext* file_system_context() { 78 return file_system_.file_system_context(); 79 } 80 81 LocalFileChangeTracker* change_tracker() { 82 return file_system_.backend()->change_tracker(); 83 } 84 85 void VerifyAndClearChange(const FileSystemURL& url, 86 const FileChange& expected_change) { 87 SCOPED_TRACE(testing::Message() << url.DebugString() << 88 " expecting:" << expected_change.DebugString()); 89 // Get the changes for URL and verify. 90 FileChangeList changes; 91 change_tracker()->GetChangesForURL(url, &changes); 92 ASSERT_EQ(1U, changes.size()); 93 SCOPED_TRACE(testing::Message() << url.DebugString() << 94 " actual:" << changes.DebugString()); 95 EXPECT_EQ(expected_change, changes.list()[0]); 96 97 // Clear the URL from the change tracker. 98 change_tracker()->ClearChangesForURL(url); 99 } 100 101 void DropChangesInTracker() { 102 change_tracker()->DropAllChanges(); 103 } 104 105 void RestoreChangesFromTrackerDB() { 106 change_tracker()->CollectLastDirtyChanges(file_system_context()); 107 } 108 109 void GetAllChangedURLs(storage::FileSystemURLSet* urls) { 110 change_tracker()->GetAllChangedURLs(urls); 111 } 112 113 base::MessageLoopForIO message_loop_; 114 base::ScopedTempDir base_dir_; 115 scoped_ptr<leveldb::Env> in_memory_env_; 116 CannedSyncableFileSystem file_system_; 117 118 private: 119 scoped_refptr<LocalFileSyncContext> sync_context_; 120 121 DISALLOW_COPY_AND_ASSIGN(LocalFileChangeTrackerTest); 122 }; 123 124 TEST_F(LocalFileChangeTrackerTest, DemoteAndPromote) { 125 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 126 127 const char kPath[] = "foo/bar"; 128 change_tracker()->OnCreateDirectory(URL(kPath)); 129 130 FileSystemURLSet urls; 131 file_system_.GetChangedURLsInTracker(&urls); 132 ASSERT_EQ(1u, urls.size()); 133 EXPECT_EQ(URL(kPath), *urls.begin()); 134 135 change_tracker()->DemoteChangesForURL(URL(kPath)); 136 137 file_system_.GetChangedURLsInTracker(&urls); 138 ASSERT_TRUE(urls.empty()); 139 140 change_tracker()->PromoteDemotedChangesForURL(URL(kPath)); 141 142 file_system_.GetChangedURLsInTracker(&urls); 143 ASSERT_EQ(1u, urls.size()); 144 EXPECT_EQ(URL(kPath), *urls.begin()); 145 146 change_tracker()->DemoteChangesForURL(URL(kPath)); 147 change_tracker()->OnRemoveDirectory(URL(kPath)); 148 149 file_system_.GetChangedURLsInTracker(&urls); 150 ASSERT_TRUE(urls.empty()); 151 } 152 153 TEST_F(LocalFileChangeTrackerTest, GetChanges) { 154 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 155 156 // Test URLs (no parent/child relationships, as we test such cases 157 // mainly in LocalFileSyncStatusTest). 158 const char kPath0[] = "test/dir a/dir"; 159 const char kPath1[] = "test/dir b"; 160 const char kPath2[] = "test/foo.txt"; 161 const char kPath3[] = "test/bar"; 162 const char kPath4[] = "temporary/dir a"; 163 const char kPath5[] = "temporary/foo"; 164 165 change_tracker()->OnCreateDirectory(URL(kPath0)); 166 change_tracker()->OnRemoveDirectory(URL(kPath0)); // Offset the create. 167 change_tracker()->OnRemoveDirectory(URL(kPath1)); 168 change_tracker()->OnCreateDirectory(URL(kPath2)); 169 change_tracker()->OnRemoveFile(URL(kPath3)); 170 change_tracker()->OnModifyFile(URL(kPath4)); 171 change_tracker()->OnCreateFile(URL(kPath5)); 172 change_tracker()->OnRemoveFile(URL(kPath5)); // Recorded as 'delete'. 173 174 FileSystemURLSet urls; 175 file_system_.GetChangedURLsInTracker(&urls); 176 177 EXPECT_EQ(5U, urls.size()); 178 EXPECT_TRUE(ContainsKey(urls, URL(kPath1))); 179 EXPECT_TRUE(ContainsKey(urls, URL(kPath2))); 180 EXPECT_TRUE(ContainsKey(urls, URL(kPath3))); 181 EXPECT_TRUE(ContainsKey(urls, URL(kPath4))); 182 EXPECT_TRUE(ContainsKey(urls, URL(kPath5))); 183 184 // Changes for kPath0 must have been offset and removed. 185 EXPECT_FALSE(ContainsKey(urls, URL(kPath0))); 186 187 // GetNextChangedURLs only returns up to max_urls (i.e. 3) urls. 188 std::deque<FileSystemURL> urls_to_process; 189 change_tracker()->GetNextChangedURLs(&urls_to_process, 3); 190 ASSERT_EQ(3U, urls_to_process.size()); 191 192 // Let it return all. 193 urls_to_process.clear(); 194 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); 195 ASSERT_EQ(5U, urls_to_process.size()); 196 197 // The changes must be in the last-modified-time order. 198 EXPECT_EQ(URL(kPath1), urls_to_process[0]); 199 EXPECT_EQ(URL(kPath2), urls_to_process[1]); 200 EXPECT_EQ(URL(kPath3), urls_to_process[2]); 201 EXPECT_EQ(URL(kPath4), urls_to_process[3]); 202 EXPECT_EQ(URL(kPath5), urls_to_process[4]); 203 204 // Modify kPath4 again. 205 change_tracker()->OnModifyFile(URL(kPath4)); 206 207 // Now the order must be changed. 208 urls_to_process.clear(); 209 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); 210 ASSERT_EQ(5U, urls_to_process.size()); 211 EXPECT_EQ(URL(kPath1), urls_to_process[0]); 212 EXPECT_EQ(URL(kPath2), urls_to_process[1]); 213 EXPECT_EQ(URL(kPath3), urls_to_process[2]); 214 EXPECT_EQ(URL(kPath5), urls_to_process[3]); 215 EXPECT_EQ(URL(kPath4), urls_to_process[4]); 216 217 // No changes to promote yet, we've demoted no changes. 218 EXPECT_FALSE(change_tracker()->PromoteDemotedChanges()); 219 220 // Demote changes for kPath1 and kPath3. 221 change_tracker()->DemoteChangesForURL(URL(kPath1)); 222 change_tracker()->DemoteChangesForURL(URL(kPath3)); 223 224 // Now we'll get no changes for kPath1 and kPath3 (it's in a separate queue). 225 urls_to_process.clear(); 226 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); 227 ASSERT_EQ(3U, urls_to_process.size()); 228 EXPECT_EQ(URL(kPath2), urls_to_process[0]); 229 EXPECT_EQ(URL(kPath5), urls_to_process[1]); 230 EXPECT_EQ(URL(kPath4), urls_to_process[2]); 231 232 // Promote changes. 233 EXPECT_TRUE(change_tracker()->PromoteDemotedChanges()); 234 235 // Now we should have kPath1 and kPath3. 236 urls_to_process.clear(); 237 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); 238 ASSERT_EQ(5U, urls_to_process.size()); 239 EXPECT_EQ(URL(kPath1), urls_to_process[0]); 240 EXPECT_EQ(URL(kPath2), urls_to_process[1]); 241 EXPECT_EQ(URL(kPath3), urls_to_process[2]); 242 EXPECT_EQ(URL(kPath5), urls_to_process[3]); 243 EXPECT_EQ(URL(kPath4), urls_to_process[4]); 244 245 // No changes to promote any more. 246 EXPECT_FALSE(change_tracker()->PromoteDemotedChanges()); 247 248 249 VerifyAndClearChange(URL(kPath1), 250 FileChange(FileChange::FILE_CHANGE_DELETE, 251 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 252 VerifyAndClearChange(URL(kPath2), 253 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 254 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 255 VerifyAndClearChange(URL(kPath3), 256 FileChange(FileChange::FILE_CHANGE_DELETE, 257 sync_file_system::SYNC_FILE_TYPE_FILE)); 258 VerifyAndClearChange(URL(kPath4), 259 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 260 sync_file_system::SYNC_FILE_TYPE_FILE)); 261 VerifyAndClearChange(URL(kPath5), 262 FileChange(FileChange::FILE_CHANGE_DELETE, 263 sync_file_system::SYNC_FILE_TYPE_FILE)); 264 } 265 266 TEST_F(LocalFileChangeTrackerTest, RestoreCreateAndModifyChanges) { 267 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 268 269 FileSystemURLSet urls; 270 271 const char kPath0[] = "file a"; 272 const char kPath1[] = "dir a"; 273 const char kPath2[] = "dir a/dir"; 274 const char kPath3[] = "dir a/file a"; 275 const char kPath4[] = "dir a/file b"; 276 277 file_system_.GetChangedURLsInTracker(&urls); 278 ASSERT_EQ(0U, urls.size()); 279 280 const std::string kData("Lorem ipsum."); 281 MockBlobURLRequestContext url_request_context(file_system_context()); 282 ScopedTextBlob blob(url_request_context, "blob_id:test", kData); 283 284 // Create files and nested directories. 285 EXPECT_EQ(base::File::FILE_OK, 286 file_system_.CreateFile(URL(kPath0))); // Creates a file. 287 EXPECT_EQ(base::File::FILE_OK, 288 file_system_.CreateDirectory(URL(kPath1))); // Creates a dir. 289 EXPECT_EQ(base::File::FILE_OK, 290 file_system_.CreateDirectory(URL(kPath2))); // Creates another dir. 291 EXPECT_EQ(base::File::FILE_OK, 292 file_system_.CreateFile(URL(kPath3))); // Creates a file. 293 EXPECT_EQ(base::File::FILE_OK, 294 file_system_.TruncateFile(URL(kPath3), 1)); // Modifies the file. 295 EXPECT_EQ(base::File::FILE_OK, 296 file_system_.CreateFile(URL(kPath4))); // Creates another file. 297 EXPECT_EQ(static_cast<int64>(kData.size()), // Modifies the file. 298 file_system_.Write(&url_request_context, 299 URL(kPath4), blob.GetBlobDataHandle())); 300 301 // Verify the changes. 302 file_system_.GetChangedURLsInTracker(&urls); 303 EXPECT_EQ(5U, urls.size()); 304 305 // Reset the changes in in-memory tracker. 306 DropChangesInTracker(); 307 308 // Make sure we have no in-memory changes in the tracker. 309 file_system_.GetChangedURLsInTracker(&urls); 310 ASSERT_EQ(0U, urls.size()); 311 312 RestoreChangesFromTrackerDB(); 313 314 // Make sure the changes are restored from the DB. 315 file_system_.GetChangedURLsInTracker(&urls); 316 EXPECT_EQ(5U, urls.size()); 317 318 VerifyAndClearChange(URL(kPath0), 319 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 320 sync_file_system::SYNC_FILE_TYPE_FILE)); 321 VerifyAndClearChange(URL(kPath1), 322 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 323 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 324 VerifyAndClearChange(URL(kPath2), 325 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 326 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 327 VerifyAndClearChange(URL(kPath3), 328 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 329 sync_file_system::SYNC_FILE_TYPE_FILE)); 330 VerifyAndClearChange(URL(kPath4), 331 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 332 sync_file_system::SYNC_FILE_TYPE_FILE)); 333 } 334 335 TEST_F(LocalFileChangeTrackerTest, RestoreRemoveChanges) { 336 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 337 338 FileSystemURLSet urls; 339 340 const char kPath0[] = "file"; 341 const char kPath1[] = "dir a"; 342 const char kPath2[] = "dir b"; 343 const char kPath3[] = "dir b/file"; 344 const char kPath4[] = "dir b/dir c"; 345 const char kPath5[] = "dir b/dir c/file"; 346 347 file_system_.GetChangedURLsInTracker(&urls); 348 ASSERT_EQ(0U, urls.size()); 349 350 // Creates and removes a same file. 351 EXPECT_EQ(base::File::FILE_OK, 352 file_system_.CreateFile(URL(kPath0))); 353 EXPECT_EQ(base::File::FILE_OK, 354 file_system_.Remove(URL(kPath0), false /* recursive */)); 355 356 // Creates and removes a same directory. 357 EXPECT_EQ(base::File::FILE_OK, 358 file_system_.CreateDirectory(URL(kPath1))); 359 EXPECT_EQ(base::File::FILE_OK, 360 file_system_.Remove(URL(kPath1), false /* recursive */)); 361 362 // Creates files and nested directories, then removes the parent directory. 363 EXPECT_EQ(base::File::FILE_OK, 364 file_system_.CreateDirectory(URL(kPath2))); 365 EXPECT_EQ(base::File::FILE_OK, 366 file_system_.CreateFile(URL(kPath3))); 367 EXPECT_EQ(base::File::FILE_OK, 368 file_system_.CreateDirectory(URL(kPath4))); 369 EXPECT_EQ(base::File::FILE_OK, 370 file_system_.CreateFile(URL(kPath5))); 371 EXPECT_EQ(base::File::FILE_OK, 372 file_system_.Remove(URL(kPath2), true /* recursive */)); 373 374 file_system_.GetChangedURLsInTracker(&urls); 375 EXPECT_EQ(3U, urls.size()); 376 377 DropChangesInTracker(); 378 379 // Make sure we have no in-memory changes in the tracker. 380 file_system_.GetChangedURLsInTracker(&urls); 381 ASSERT_EQ(0U, urls.size()); 382 383 RestoreChangesFromTrackerDB(); 384 385 // Make sure the changes are restored from the DB. 386 file_system_.GetChangedURLsInTracker(&urls); 387 // Since directories to have been reverted (kPath1, kPath2, kPath4) are 388 // treated as FILE_CHANGE_DELETE, the number of changes should be 6. 389 EXPECT_EQ(6U, urls.size()); 390 391 VerifyAndClearChange(URL(kPath0), 392 FileChange(FileChange::FILE_CHANGE_DELETE, 393 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 394 VerifyAndClearChange(URL(kPath1), 395 FileChange(FileChange::FILE_CHANGE_DELETE, 396 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 397 VerifyAndClearChange(URL(kPath2), 398 FileChange(FileChange::FILE_CHANGE_DELETE, 399 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 400 VerifyAndClearChange(URL(kPath3), 401 FileChange(FileChange::FILE_CHANGE_DELETE, 402 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 403 VerifyAndClearChange(URL(kPath4), 404 FileChange(FileChange::FILE_CHANGE_DELETE, 405 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 406 VerifyAndClearChange(URL(kPath5), 407 FileChange(FileChange::FILE_CHANGE_DELETE, 408 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 409 } 410 411 TEST_F(LocalFileChangeTrackerTest, RestoreCopyChanges) { 412 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 413 414 FileSystemURLSet urls; 415 416 const char kPath0[] = "file a"; 417 const char kPath1[] = "dir a"; 418 const char kPath2[] = "dir a/dir"; 419 const char kPath3[] = "dir a/file a"; 420 const char kPath4[] = "dir a/file b"; 421 422 const char kPath0Copy[] = "file b"; // To be copied from kPath0 423 const char kPath1Copy[] = "dir b"; // To be copied from kPath1 424 const char kPath2Copy[] = "dir b/dir"; // To be copied from kPath2 425 const char kPath3Copy[] = "dir b/file a"; // To be copied from kPath3 426 const char kPath4Copy[] = "dir b/file b"; // To be copied from kPath4 427 428 file_system_.GetChangedURLsInTracker(&urls); 429 ASSERT_EQ(0U, urls.size()); 430 431 const std::string kData("Lorem ipsum."); 432 MockBlobURLRequestContext url_request_context(file_system_context()); 433 ScopedTextBlob blob(url_request_context, "blob_id:test", kData); 434 435 // Create files and nested directories. 436 EXPECT_EQ(base::File::FILE_OK, 437 file_system_.CreateFile(URL(kPath0))); // Creates a file. 438 EXPECT_EQ(base::File::FILE_OK, 439 file_system_.CreateDirectory(URL(kPath1))); // Creates a dir. 440 EXPECT_EQ(base::File::FILE_OK, 441 file_system_.CreateDirectory(URL(kPath2))); // Creates another dir. 442 EXPECT_EQ(base::File::FILE_OK, 443 file_system_.CreateFile(URL(kPath3))); // Creates a file. 444 EXPECT_EQ(base::File::FILE_OK, 445 file_system_.TruncateFile(URL(kPath3), 1)); // Modifies the file. 446 EXPECT_EQ(base::File::FILE_OK, 447 file_system_.CreateFile(URL(kPath4))); // Creates another file. 448 EXPECT_EQ(static_cast<int64>(kData.size()), 449 file_system_.Write(&url_request_context, // Modifies the file. 450 URL(kPath4), blob.GetBlobDataHandle())); 451 452 // Verify we have 5 changes for preparation. 453 file_system_.GetChangedURLsInTracker(&urls); 454 EXPECT_EQ(5U, urls.size()); 455 change_tracker()->ClearChangesForURL(URL(kPath0)); 456 change_tracker()->ClearChangesForURL(URL(kPath1)); 457 change_tracker()->ClearChangesForURL(URL(kPath2)); 458 change_tracker()->ClearChangesForURL(URL(kPath3)); 459 change_tracker()->ClearChangesForURL(URL(kPath4)); 460 461 // Make sure we have no changes. 462 file_system_.GetChangedURLsInTracker(&urls); 463 EXPECT_TRUE(urls.empty()); 464 465 // Copy the file and the parent directory. 466 EXPECT_EQ(base::File::FILE_OK, 467 file_system_.Copy(URL(kPath0), URL(kPath0Copy))); // Copy the file. 468 EXPECT_EQ(base::File::FILE_OK, 469 file_system_.Copy(URL(kPath1), URL(kPath1Copy))); // Copy the dir. 470 471 file_system_.GetChangedURLsInTracker(&urls); 472 EXPECT_EQ(5U, urls.size()); 473 DropChangesInTracker(); 474 475 // Make sure we have no in-memory changes in the tracker. 476 file_system_.GetChangedURLsInTracker(&urls); 477 ASSERT_EQ(0U, urls.size()); 478 479 RestoreChangesFromTrackerDB(); 480 481 // Make sure the changes are restored from the DB. 482 file_system_.GetChangedURLsInTracker(&urls); 483 EXPECT_EQ(5U, urls.size()); 484 485 VerifyAndClearChange(URL(kPath0Copy), 486 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 487 sync_file_system::SYNC_FILE_TYPE_FILE)); 488 VerifyAndClearChange(URL(kPath1Copy), 489 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 490 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 491 VerifyAndClearChange(URL(kPath2Copy), 492 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 493 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 494 VerifyAndClearChange(URL(kPath3Copy), 495 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 496 sync_file_system::SYNC_FILE_TYPE_FILE)); 497 VerifyAndClearChange(URL(kPath4Copy), 498 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 499 sync_file_system::SYNC_FILE_TYPE_FILE)); 500 } 501 502 TEST_F(LocalFileChangeTrackerTest, RestoreMoveChanges) { 503 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 504 505 FileSystemURLSet urls; 506 507 const char kPath0[] = "file a"; 508 const char kPath1[] = "dir a"; 509 const char kPath2[] = "dir a/file"; 510 const char kPath3[] = "dir a/dir"; 511 const char kPath4[] = "dir a/dir/file"; 512 513 const char kPath5[] = "file b"; // To be moved from kPath0. 514 const char kPath6[] = "dir b"; // To be moved from kPath1. 515 const char kPath7[] = "dir b/file"; // To be moved from kPath2. 516 const char kPath8[] = "dir b/dir"; // To be moved from kPath3. 517 const char kPath9[] = "dir b/dir/file"; // To be moved from kPath4. 518 519 file_system_.GetChangedURLsInTracker(&urls); 520 ASSERT_EQ(0U, urls.size()); 521 522 // Create files and nested directories. 523 EXPECT_EQ(base::File::FILE_OK, 524 file_system_.CreateFile(URL(kPath0))); 525 EXPECT_EQ(base::File::FILE_OK, 526 file_system_.CreateDirectory(URL(kPath1))); 527 EXPECT_EQ(base::File::FILE_OK, 528 file_system_.CreateFile(URL(kPath2))); 529 EXPECT_EQ(base::File::FILE_OK, 530 file_system_.CreateDirectory(URL(kPath3))); 531 EXPECT_EQ(base::File::FILE_OK, 532 file_system_.CreateFile(URL(kPath4))); 533 534 // Verify we have 5 changes for preparation. 535 file_system_.GetChangedURLsInTracker(&urls); 536 EXPECT_EQ(5U, urls.size()); 537 change_tracker()->ClearChangesForURL(URL(kPath0)); 538 change_tracker()->ClearChangesForURL(URL(kPath1)); 539 change_tracker()->ClearChangesForURL(URL(kPath2)); 540 change_tracker()->ClearChangesForURL(URL(kPath3)); 541 change_tracker()->ClearChangesForURL(URL(kPath4)); 542 543 // Make sure we have no changes. 544 file_system_.GetChangedURLsInTracker(&urls); 545 EXPECT_TRUE(urls.empty()); 546 547 // Move the file and the parent directory. 548 EXPECT_EQ(base::File::FILE_OK, 549 file_system_.Move(URL(kPath0), URL(kPath5))); 550 EXPECT_EQ(base::File::FILE_OK, 551 file_system_.Move(URL(kPath1), URL(kPath6))); 552 553 file_system_.GetChangedURLsInTracker(&urls); 554 EXPECT_EQ(10U, urls.size()); 555 556 DropChangesInTracker(); 557 558 // Make sure we have no in-memory changes in the tracker. 559 file_system_.GetChangedURLsInTracker(&urls); 560 ASSERT_EQ(0U, urls.size()); 561 562 RestoreChangesFromTrackerDB(); 563 564 // Make sure the changes are restored from the DB. 565 file_system_.GetChangedURLsInTracker(&urls); 566 // Deletion for child files in the deleted directory cannot be restored, 567 // so we will only have 8 changes. 568 EXPECT_EQ(10U, urls.size()); 569 570 VerifyAndClearChange(URL(kPath0), 571 FileChange(FileChange::FILE_CHANGE_DELETE, 572 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 573 VerifyAndClearChange(URL(kPath1), 574 FileChange(FileChange::FILE_CHANGE_DELETE, 575 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 576 VerifyAndClearChange(URL(kPath3), 577 FileChange(FileChange::FILE_CHANGE_DELETE, 578 sync_file_system::SYNC_FILE_TYPE_UNKNOWN)); 579 VerifyAndClearChange(URL(kPath5), 580 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 581 sync_file_system::SYNC_FILE_TYPE_FILE)); 582 VerifyAndClearChange(URL(kPath6), 583 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 584 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 585 VerifyAndClearChange(URL(kPath7), 586 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 587 sync_file_system::SYNC_FILE_TYPE_FILE)); 588 VerifyAndClearChange(URL(kPath8), 589 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 590 sync_file_system::SYNC_FILE_TYPE_DIRECTORY)); 591 VerifyAndClearChange(URL(kPath9), 592 FileChange(FileChange::FILE_CHANGE_ADD_OR_UPDATE, 593 sync_file_system::SYNC_FILE_TYPE_FILE)); 594 } 595 596 TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveCopy) { 597 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 598 599 FileSystemURLSet urls; 600 601 const char kPath0[] = "dir a"; 602 const char kPath1[] = "dir a/file"; 603 const char kPath2[] = "dir a/dir"; 604 605 const char kPath0Copy[] = "dir b"; 606 const char kPath1Copy[] = "dir b/file"; 607 const char kPath2Copy[] = "dir b/dir"; 608 609 // Creates kPath0,1,2 and then copies them all. 610 EXPECT_EQ(base::File::FILE_OK, 611 file_system_.CreateDirectory(URL(kPath0))); 612 EXPECT_EQ(base::File::FILE_OK, 613 file_system_.CreateFile(URL(kPath1))); 614 EXPECT_EQ(base::File::FILE_OK, 615 file_system_.CreateDirectory(URL(kPath2))); 616 EXPECT_EQ(base::File::FILE_OK, 617 file_system_.Copy(URL(kPath0), URL(kPath0Copy))); 618 619 std::deque<FileSystemURL> urls_to_process; 620 change_tracker()->GetNextChangedURLs(&urls_to_process, 0); 621 ASSERT_EQ(6U, urls_to_process.size()); 622 623 // Creation must have occured first. 624 EXPECT_EQ(URL(kPath0), urls_to_process[0]); 625 EXPECT_EQ(URL(kPath1), urls_to_process[1]); 626 EXPECT_EQ(URL(kPath2), urls_to_process[2]); 627 628 // Then recursive copy took place. The exact order cannot be determined 629 // but the parent directory must have been created first. 630 EXPECT_EQ(URL(kPath0Copy), urls_to_process[3]); 631 EXPECT_TRUE(URL(kPath1Copy) == urls_to_process[4] || 632 URL(kPath2Copy) == urls_to_process[4]); 633 EXPECT_TRUE(URL(kPath1Copy) == urls_to_process[5] || 634 URL(kPath2Copy) == urls_to_process[5]); 635 } 636 637 TEST_F(LocalFileChangeTrackerTest, NextChangedURLsWithRecursiveRemove) { 638 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 639 640 const char kPath0[] = "dir a"; 641 const char kPath1[] = "dir a/file1"; 642 const char kPath2[] = "dir a/file2"; 643 644 // Creates kPath0,1,2 and then removes them all. 645 EXPECT_EQ(base::File::FILE_OK, 646 file_system_.CreateDirectory(URL(kPath0))); 647 EXPECT_EQ(base::File::FILE_OK, 648 file_system_.CreateFile(URL(kPath1))); 649 EXPECT_EQ(base::File::FILE_OK, 650 file_system_.CreateFile(URL(kPath2))); 651 EXPECT_EQ(base::File::FILE_OK, 652 file_system_.Remove(URL(kPath0), true /* recursive */)); 653 654 FileSystemURLSet urls; 655 GetAllChangedURLs(&urls); 656 657 // This is actually not really desirable, but since the directory 658 // creation and deletion have been offset now we only have two 659 // file deletion changes. 660 // 661 // NOTE: This will cause 2 local sync for deleting nonexistent files 662 // on the remote side. 663 // 664 // TODO(kinuko): For micro optimization we could probably restore the ADD 665 // change type (other than ADD_OR_UPDATE) and offset file ADD+DELETE 666 // changes too. 667 ASSERT_EQ(2U, urls.size()); 668 669 // The exact order of recursive removal cannot be determined. 670 EXPECT_TRUE(ContainsKey(urls, URL(kPath1))); 671 EXPECT_TRUE(ContainsKey(urls, URL(kPath2))); 672 } 673 674 TEST_F(LocalFileChangeTrackerTest, ResetForFileSystem) { 675 EXPECT_EQ(base::File::FILE_OK, file_system_.OpenFileSystem()); 676 677 const char kPath0[] = "dir a"; 678 const char kPath1[] = "dir a/file"; 679 const char kPath2[] = "dir a/subdir"; 680 const char kPath3[] = "dir b"; 681 682 EXPECT_EQ(base::File::FILE_OK, 683 file_system_.CreateDirectory(URL(kPath0))); 684 EXPECT_EQ(base::File::FILE_OK, 685 file_system_.CreateFile(URL(kPath1))); 686 EXPECT_EQ(base::File::FILE_OK, 687 file_system_.CreateDirectory(URL(kPath2))); 688 EXPECT_EQ(base::File::FILE_OK, 689 file_system_.CreateDirectory(URL(kPath3))); 690 691 FileSystemURLSet urls; 692 GetAllChangedURLs(&urls); 693 EXPECT_EQ(4u, urls.size()); 694 EXPECT_TRUE(ContainsKey(urls, URL(kPath0))); 695 EXPECT_TRUE(ContainsKey(urls, URL(kPath1))); 696 EXPECT_TRUE(ContainsKey(urls, URL(kPath2))); 697 EXPECT_TRUE(ContainsKey(urls, URL(kPath3))); 698 699 // Reset all changes for the file system. 700 change_tracker()->ResetForFileSystem( 701 file_system_.origin(), file_system_.type()); 702 703 GetAllChangedURLs(&urls); 704 EXPECT_TRUE(urls.empty()); 705 706 // Make sure they're gone from the database too. 707 DropChangesInTracker(); 708 RestoreChangesFromTrackerDB(); 709 710 GetAllChangedURLs(&urls); 711 EXPECT_TRUE(urls.empty()); 712 } 713 714 } // namespace sync_file_system 715