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