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