github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/test/cr_basic_conflicts_test.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 // These tests all do multiple operations while a user is unstaged. 6 7 package test 8 9 import ( 10 "os" 11 "testing" 12 "time" 13 14 "github.com/keybase/client/go/kbfs/libkbfs" 15 ) 16 17 // bob and alice both write(to the same file), 18 func testCrConflictWriteFile(t *testing.T) { 19 test(t, 20 users("alice", "bob"), 21 as(alice, 22 mkfile("a/b", "hello"), 23 ), 24 as(bob, 25 disableUpdates(), 26 ), 27 as(alice, 28 write("a/b", "world"), 29 ), 30 as(bob, noSync(), 31 write("a/b", "uh oh"), 32 reenableUpdates(), 33 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 34 read("a/b", "world"), 35 read(crname("a/b", bob), "uh oh"), 36 ), 37 as(alice, 38 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 39 read("a/b", "world"), 40 read(crname("a/b", bob), "uh oh"), 41 ), 42 ) 43 } 44 45 func TestCrConflictWriteFile(t *testing.T) { 46 testCrConflictWriteFile(t) 47 } 48 49 func TestCrConflictWriteFileWithObfuscation(t *testing.T) { 50 oldEnv := os.Getenv(libkbfs.EnvKeybaseTestObfuscateLogsForTest) 51 os.Setenv(libkbfs.EnvKeybaseTestObfuscateLogsForTest, "1") 52 defer func() { 53 os.Setenv(libkbfs.EnvKeybaseTestObfuscateLogsForTest, oldEnv) 54 }() 55 testCrConflictWriteFile(t) 56 } 57 58 // bob and alice both create the same entry with different types 59 func TestCrConflictCreateWithDifferentTypes(t *testing.T) { 60 test(t, 61 users("alice", "bob"), 62 as(alice, 63 mkdir("a"), 64 mkfile("a/b", "hello"), 65 ), 66 as(bob, 67 disableUpdates(), 68 ), 69 as(alice, 70 mkdir("a/c"), 71 ), 72 as(bob, noSync(), 73 mkfile("a/c", ""), 74 reenableUpdates(), 75 lsdir("a/", m{"b$": "FILE", "c$": "DIR", 76 crnameEsc("c", bob): "FILE"}), 77 read("a/b", "hello"), 78 lsdir("a/c", m{}), 79 read(crname("a/c", bob), ""), 80 ), 81 as(alice, 82 lsdir("a/", m{"b$": "FILE", "c$": "DIR", 83 crnameEsc("c", bob): "FILE"}), 84 read("a/b", "hello"), 85 lsdir("a/c", m{}), 86 read(crname("a/c", bob), ""), 87 ), 88 ) 89 } 90 91 // bob and alice both create the same file with different types 92 func TestCrConflictCreateFileWithDifferentTypes(t *testing.T) { 93 test(t, 94 skip("dokan", "Does not work with Dokan."), 95 users("alice", "bob"), 96 as(alice, 97 mkdir("a"), 98 mkfile("a/b", "hello"), 99 ), 100 as(bob, 101 disableUpdates(), 102 ), 103 as(alice, 104 mkfile("a/c", ""), 105 ), 106 as(bob, noSync(), 107 link("a/c", "b"), 108 reenableUpdates(), 109 lsdir("a/", m{"b$": "FILE", "c$": "FILE", 110 crnameEsc("c", bob): "SYM"}), 111 read("a/b", "hello"), 112 read("a/c", ""), 113 read(crname("a/c", bob), "hello"), 114 ), 115 as(alice, 116 lsdir("a/", m{"b$": "FILE", "c$": "FILE", 117 crnameEsc("c", bob): "SYM"}), 118 read("a/b", "hello"), 119 read("a/c", ""), 120 read(crname("a/c", bob), "hello"), 121 ), 122 ) 123 } 124 125 // bob and alice both create the same symlink with different contents 126 func TestCrConflictCreateSymlinkWithDifferentContents(t *testing.T) { 127 test(t, 128 skip("dokan", "Does not work with Dokan."), 129 users("alice", "bob"), 130 as(alice, 131 mkdir("a"), 132 mkfile("a/b", "hello"), 133 mkfile("a/c", "world"), 134 ), 135 as(bob, 136 disableUpdates(), 137 ), 138 as(alice, 139 link("a/d", "b"), 140 ), 141 as(bob, noSync(), 142 link("a/d", "c"), 143 reenableUpdates(), 144 lsdir("a/", m{"b$": "FILE", "c$": "FILE", "d$": "SYM", 145 crnameEsc("d", bob): "SYM"}), 146 read("a/b", "hello"), 147 read("a/c", "world"), 148 read("a/d", "hello"), 149 read(crname("a/d", bob), "world"), 150 ), 151 as(alice, 152 lsdir("a/", m{"b$": "FILE", "c$": "FILE", "d$": "SYM", 153 crnameEsc("d", bob): "SYM"}), 154 read("a/b", "hello"), 155 read("a/c", "world"), 156 read("a/d", "hello"), 157 read(crname("a/d", bob), "world"), 158 ), 159 ) 160 } 161 162 // bob and alice both write(to the same file), but on a non-default day. 163 func TestCrConflictWriteFileWithAddTime(t *testing.T) { 164 timeInc := 25 * time.Hour 165 test(t, 166 users("alice", "bob"), 167 as(alice, 168 mkfile("a/b", "hello"), 169 ), 170 as(bob, 171 disableUpdates(), 172 ), 173 as(alice, 174 addTime(timeInc), 175 write("a/b", "world"), 176 ), 177 as(bob, noSync(), 178 write("a/b", "uh oh"), 179 reenableUpdates(), 180 lsdir("a/", m{"b$": "FILE", 181 crnameAtTimeEsc("b", bob, timeInc): "FILE"}), 182 read("a/b", "world"), 183 read(crnameAtTime("a/b", bob, timeInc), "uh oh"), 184 ), 185 as(alice, 186 lsdir("a/", m{"b$": "FILE", 187 crnameAtTimeEsc("b", bob, timeInc): "FILE"}), 188 read("a/b", "world"), 189 read(crnameAtTime("a/b", bob, timeInc), "uh oh"), 190 ), 191 ) 192 } 193 194 // bob and alice both write(to the same file), 195 func TestCrConflictWriteFileWithExtension(t *testing.T) { 196 test(t, 197 users("alice", "bob"), 198 as(alice, 199 mkfile("a/foo.tar.gz", "hello"), 200 ), 201 as(bob, 202 disableUpdates(), 203 ), 204 as(alice, 205 write("a/foo.tar.gz", "world"), 206 ), 207 as(bob, noSync(), 208 write("a/foo.tar.gz", "uh oh"), 209 reenableUpdates(), 210 lsdir("a/", m{"foo.tar.gz$": "FILE", crnameEsc("foo.tar.gz", bob): "FILE"}), 211 read("a/foo.tar.gz", "world"), 212 read(crname("a/foo.tar.gz", bob), "uh oh"), 213 ), 214 as(alice, 215 lsdir("a/", m{"foo.tar.gz$": "FILE", crnameEsc("foo.tar.gz", bob): "FILE"}), 216 read("a/foo.tar.gz", "world"), 217 read(crname("a/foo.tar.gz", bob), "uh oh"), 218 ), 219 ) 220 } 221 222 // bob and alice both create the same file 223 func TestCrConflictCreateFile(t *testing.T) { 224 test(t, 225 users("alice", "bob"), 226 as(alice, 227 mkdir("a"), 228 ), 229 as(bob, 230 disableUpdates(), 231 ), 232 as(alice, 233 write("a/b", "world"), 234 ), 235 as(bob, noSync(), 236 write("a/b", "uh oh"), 237 reenableUpdates(), 238 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 239 read("a/b", "world"), 240 read(crname("a/b", bob), "uh oh"), 241 ), 242 as(alice, 243 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 244 read("a/b", "world"), 245 read(crname("a/b", bob), "uh oh"), 246 ), 247 ) 248 } 249 250 // alice writes and removes a file, while bob writes it. Regression 251 // test for KBFS-2507. 252 func TestCrConflictWriteVsModifiedRemovedFile(t *testing.T) { 253 test(t, 254 skip("dokan", "SetEx is a no-op on Dokan, thus no conflict"), 255 users("alice", "bob"), 256 as(alice, 257 mkfile("a", "hello"), 258 ), 259 as(bob, 260 disableUpdates(), 261 ), 262 as(alice, 263 write("a", "goodbye"), 264 rm("a"), 265 ), 266 as(bob, noSync(), 267 write("a", "hello world"), 268 reenableUpdates(), 269 lsdir("", m{"a$": "FILE"}), 270 read("a", "hello world"), 271 ), 272 as(alice, 273 lsdir("", m{"a$": "FILE"}), 274 read("a", "hello world"), 275 ), 276 ) 277 } 278 279 // alice setattr's a file, while bob removes, recreates and writes to 280 // a file of the same name. Regression test for KBFS-668. 281 func TestCrConflictSetattrVsRecreatedFileInRoot(t *testing.T) { 282 test(t, 283 skip("dokan", "SetEx is a no-op on Dokan, thus no conflict"), 284 users("alice", "bob"), 285 as(alice, 286 mkfile("a", "hello"), 287 ), 288 as(bob, 289 disableUpdates(), 290 ), 291 as(alice, 292 setex("a", true), 293 ), 294 as(bob, noSync(), 295 write("a", "uh oh"), 296 rm("a"), 297 mkfile("a", "world"), 298 reenableUpdates(), 299 lsdir("", m{"a$": "EXEC", crnameEsc("a", bob): "FILE"}), 300 read("a", "hello"), 301 read(crname("a", bob), "world"), 302 checkPrevRevisions("a", []uint8{1}), 303 checkPrevRevisions(crname("a", bob), []uint8{1}), 304 ), 305 as(alice, 306 lsdir("", m{"a$": "EXEC", crnameEsc("a", bob): "FILE"}), 307 read("a", "hello"), 308 read(crname("a", bob), "world"), 309 checkPrevRevisions("a", []uint8{1}), 310 checkPrevRevisions(crname("a", bob), []uint8{1}), 311 ), 312 ) 313 } 314 315 // bob creates a directory with the same name that alice used for a file 316 func TestCrConflictCauseRenameOfMergedFile(t *testing.T) { 317 test(t, 318 users("alice", "bob"), 319 as(alice, 320 mkdir("a"), 321 ), 322 as(bob, 323 disableUpdates(), 324 ), 325 as(alice, 326 write("a/b", "world"), 327 ), 328 as(bob, noSync(), 329 write("a/b/c", "uh oh"), 330 reenableUpdates(), 331 lsdir("a/", m{"b$": "DIR", crnameEsc("b", alice): "FILE"}), 332 read(crname("a/b", alice), "world"), 333 read("a/b/c", "uh oh"), 334 ), 335 as(alice, 336 lsdir("a/", m{"b$": "DIR", crnameEsc("b", alice): "FILE"}), 337 read(crname("a/b", alice), "world"), 338 read("a/b/c", "uh oh"), 339 ), 340 ) 341 } 342 343 // bob creates a directory with the same name that alice used for a 344 // file that used to exist at that location 345 func TestCrConflictCauseRenameOfMergedRecreatedFile(t *testing.T) { 346 test(t, 347 users("alice", "bob"), 348 as(alice, 349 mkdir("a"), 350 write("a/b", "hello"), 351 ), 352 as(bob, 353 disableUpdates(), 354 ), 355 as(alice, 356 write("a/b", "world"), 357 ), 358 as(bob, noSync(), 359 rm("a/b"), 360 write("a/b/c", "uh oh"), 361 reenableUpdates(), 362 lsdir("a/", m{"b$": "DIR", crnameEsc("b", alice): "FILE"}), 363 read(crname("a/b", alice), "world"), 364 read("a/b/c", "uh oh"), 365 checkPrevRevisions("a", []uint8{1, 2, 3}), 366 ), 367 as(alice, 368 lsdir("a/", m{"b$": "DIR", crnameEsc("b", alice): "FILE"}), 369 read(crname("a/b", alice), "world"), 370 read("a/b/c", "uh oh"), 371 checkPrevRevisions("a", []uint8{1, 2, 3}), 372 ), 373 ) 374 } 375 376 // bob renames a file over one modified by alice. 377 func TestCrConflictUnmergedRenameFileOverModifiedFile(t *testing.T) { 378 test(t, 379 users("alice", "bob"), 380 as(alice, 381 write("a/b", "hello"), 382 write("a/c", "world"), 383 ), 384 as(bob, 385 disableUpdates(), 386 ), 387 as(alice, 388 write("a/b", "uh oh"), 389 ), 390 as(bob, noSync(), 391 rename("a/c", "a/b"), 392 reenableUpdates(), 393 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 394 read("a/b", "uh oh"), 395 read(crname("a/b", bob), "world"), 396 ), 397 as(alice, 398 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 399 read("a/b", "uh oh"), 400 read(crname("a/b", bob), "world"), 401 ), 402 ) 403 } 404 405 // bob modifies and renames a file that was modified by alice. 406 func TestCrConflictUnmergedRenameModifiedFile(t *testing.T) { 407 test(t, 408 users("alice", "bob"), 409 as(alice, 410 write("a/b", "hello"), 411 ), 412 as(bob, 413 disableUpdates(), 414 ), 415 as(alice, 416 write("a/b", "world"), 417 ), 418 as(bob, noSync(), 419 write("a/b", "uh oh"), 420 rename("a/b", "a/c"), 421 reenableUpdates(), 422 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 423 read("a/b", "world"), 424 read("a/c", "uh oh"), 425 ), 426 as(alice, 427 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 428 read("a/b", "world"), 429 read("a/c", "uh oh"), 430 ), 431 ) 432 } 433 434 // bob modifies and renames a file that was modified by alice, while 435 // alice also made a file with the new name. 436 func TestCrConflictUnmergedRenameModifiedFileAndConflictFile(t *testing.T) { 437 test(t, 438 users("alice", "bob"), 439 as(alice, 440 write("a/b", "hello"), 441 ), 442 as(bob, 443 disableUpdates(), 444 ), 445 as(alice, 446 write("a/b", "world"), 447 mkfile("a/c", "CONFLICT"), 448 ), 449 as(bob, noSync(), 450 write("a/b", "uh oh"), 451 rename("a/b", "a/c"), 452 reenableUpdates(), 453 lsdir("a/", m{"b$": "FILE", "c$": "FILE", crnameEsc("c", bob): "FILE"}), 454 read("a/b", "world"), 455 read("a/c", "CONFLICT"), 456 read(crname("a/c", bob), "uh oh"), 457 ), 458 as(alice, 459 lsdir("a/", m{"b$": "FILE", "c$": "FILE", crnameEsc("c", bob): "FILE"}), 460 read("a/b", "world"), 461 read("a/c", "CONFLICT"), 462 read(crname("a/c", bob), "uh oh"), 463 ), 464 ) 465 } 466 467 // bob modifies and renames (to another dir) a file that was modified 468 // by alice. 469 func TestCrConflictUnmergedRenameAcrossDirsModifiedFile(t *testing.T) { 470 test(t, 471 users("alice", "bob"), 472 as(alice, 473 write("a/b", "hello"), 474 ), 475 as(bob, 476 disableUpdates(), 477 ), 478 as(alice, 479 write("a/b", "world"), 480 ), 481 as(bob, noSync(), 482 write("a/b", "uh oh"), 483 rename("a/b", "b/c"), 484 reenableUpdates(), 485 lsdir("a/", m{"b$": "FILE"}), 486 read("a/b", "world"), 487 lsdir("b/", m{"c$": "FILE"}), 488 read("b/c", "uh oh"), 489 ), 490 as(alice, 491 lsdir("a/", m{"b$": "FILE"}), 492 read("a/b", "world"), 493 lsdir("b/", m{"c$": "FILE"}), 494 read("b/c", "uh oh"), 495 ), 496 ) 497 } 498 499 // bob sets the mtime on and renames a file that had its mtime set by alice. 500 func TestCrConflictUnmergedRenameSetMtimeFile(t *testing.T) { 501 targetMtime1 := time.Now().Add(1 * time.Minute) 502 targetMtime2 := targetMtime1.Add(1 * time.Minute) 503 test(t, 504 users("alice", "bob"), 505 as(alice, 506 write("a/b", "hello"), 507 ), 508 as(bob, 509 disableUpdates(), 510 ), 511 as(alice, 512 setmtime("a/b", targetMtime1), 513 ), 514 as(bob, noSync(), 515 setmtime("a/b", targetMtime2), 516 rename("a/b", "a/c"), 517 reenableUpdates(), 518 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 519 mtime("a/b", targetMtime1), 520 mtime("a/c", targetMtime2), 521 ), 522 as(alice, 523 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 524 mtime("a/b", targetMtime1), 525 mtime("a/c", targetMtime2), 526 ), 527 ) 528 } 529 530 // bob renames a file from a new directory over one modified by alice. 531 func TestCrConflictUnmergedRenameFileInNewDirOverModifiedFile(t *testing.T) { 532 test(t, 533 users("alice", "bob"), 534 as(alice, 535 write("a/b", "hello"), 536 write("a/c", "world"), 537 ), 538 as(bob, 539 disableUpdates(), 540 ), 541 as(alice, 542 write("a/b", "uh oh"), 543 ), 544 as(bob, noSync(), 545 rename("a/c", "e/c"), 546 rename("e/c", "a/b"), 547 reenableUpdates(), 548 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 549 lsdir("e/", m{}), 550 read("a/b", "uh oh"), 551 read(crname("a/b", bob), "world"), 552 ), 553 as(alice, 554 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 555 lsdir("e/", m{}), 556 read("a/b", "uh oh"), 557 read(crname("a/b", bob), "world"), 558 ), 559 ) 560 } 561 562 // bob renames an existing directory over one created by alice. 563 // TODO: it would be better if this weren't a conflict. 564 func TestCrConflictUnmergedRenamedDir(t *testing.T) { 565 test(t, 566 users("alice", "bob"), 567 as(alice, 568 write("a/b/c", "hello"), 569 ), 570 as(bob, 571 disableUpdates(), 572 ), 573 as(alice, 574 write("a/d/e", "world"), 575 ), 576 as(bob, noSync(), 577 write("a/b/f", "uh oh"), 578 rename("a/b", "a/d"), 579 reenableUpdates(), 580 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob): "DIR"}), 581 lsdir("a/d", m{"e": "FILE"}), 582 lsdir(crname("a/d", bob), m{"c": "FILE", "f": "FILE"}), 583 read(crname("a/d", bob)+"/c", "hello"), 584 read("a/d/e", "world"), 585 read(crname("a/d", bob)+"/f", "uh oh"), 586 ), 587 as(alice, 588 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob): "DIR"}), 589 lsdir("a/d", m{"e": "FILE"}), 590 lsdir(crname("a/d", bob), m{"c": "FILE", "f": "FILE"}), 591 read(crname("a/d", bob)+"/c", "hello"), 592 read("a/d/e", "world"), 593 read(crname("a/d", bob)+"/f", "uh oh"), 594 ), 595 ) 596 } 597 598 // bob renames a directory over one made non-empty by alice 599 func TestCrConflictUnmergedRenameDirOverNonemptyDir(t *testing.T) { 600 test(t, 601 users("alice", "bob"), 602 as(alice, 603 mkdir("a/b"), 604 mkfile("a/c/d", "hello"), 605 ), 606 as(bob, 607 disableUpdates(), 608 ), 609 as(alice, 610 mkfile("a/b/e", "uh oh"), 611 ), 612 as(bob, noSync(), 613 rm("a/b"), 614 rename("a/c", "a/b"), 615 reenableUpdates(), 616 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "DIR"}), 617 lsdir("a/b", m{"e": "FILE"}), 618 lsdir(crname("a/b", bob), m{"d": "FILE"}), 619 ), 620 as(alice, 621 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "DIR"}), 622 lsdir("a/b", m{"e": "FILE"}), 623 lsdir(crname("a/b", bob), m{"d": "FILE"}), 624 ), 625 ) 626 } 627 628 // alice renames an existing directory over one created by bob. TODO: 629 // it would be better if this weren't a conflict. 630 func TestCrConflictMergedRenamedDir(t *testing.T) { 631 test(t, 632 users("alice", "bob"), 633 as(alice, 634 write("a/b/c", "hello"), 635 ), 636 as(bob, 637 disableUpdates(), 638 ), 639 as(alice, 640 write("a/b/f", "uh oh"), 641 rename("a/b", "a/d"), 642 ), 643 as(bob, noSync(), 644 write("a/d/e", "world"), 645 reenableUpdates(), 646 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob): "DIR"}), 647 lsdir("a/d", m{"c": "FILE", "f": "FILE"}), 648 read("a/d/c", "hello"), 649 read(crname("a/d", bob)+"/e", "world"), 650 read("a/d/f", "uh oh"), 651 ), 652 as(alice, 653 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob): "DIR"}), 654 lsdir("a/d", m{"c": "FILE", "f": "FILE"}), 655 read("a/d/c", "hello"), 656 read(crname("a/d", bob)+"/e", "world"), 657 read("a/d/f", "uh oh"), 658 ), 659 ) 660 } 661 662 // alice renames a file over one modified by bob. 663 func TestCrConflictMergedRenameFileOverModifiedFile(t *testing.T) { 664 test(t, 665 users("alice", "bob"), 666 as(alice, 667 write("a/b", "hello"), 668 write("a/c", "world"), 669 ), 670 as(bob, 671 disableUpdates(), 672 ), 673 as(alice, 674 rename("a/c", "a/b"), 675 ), 676 as(bob, noSync(), 677 write("a/b", "uh oh"), 678 reenableUpdates(), 679 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 680 read("a/b", "world"), 681 read(crname("a/b", bob), "uh oh"), 682 ), 683 as(alice, 684 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 685 read("a/b", "world"), 686 read(crname("a/b", bob), "uh oh"), 687 ), 688 ) 689 } 690 691 // alice modifies and renames a file that was modified by bob. 692 func TestCrConflictMergedRenameModifiedFile(t *testing.T) { 693 test(t, 694 users("alice", "bob"), 695 as(alice, 696 write("a/b", "hello"), 697 ), 698 as(bob, 699 disableUpdates(), 700 ), 701 as(alice, 702 write("a/b", "world"), 703 rename("a/b", "a/c"), 704 ), 705 as(bob, noSync(), 706 write("a/b", "uh oh"), 707 reenableUpdates(), 708 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 709 read("a/b", "uh oh"), 710 read("a/c", "world"), 711 ), 712 as(alice, 713 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 714 read("a/b", "uh oh"), 715 read("a/c", "world"), 716 ), 717 ) 718 } 719 720 // alice modifies and renames a file that was modified by bob, while 721 // bob also made a file with the new name. 722 func TestCrConflictMergedRenameModifiedFileAndConflictFile(t *testing.T) { 723 test(t, 724 users("alice", "bob"), 725 as(alice, 726 write("a/b", "hello"), 727 ), 728 as(bob, 729 disableUpdates(), 730 ), 731 as(alice, 732 write("a/b", "uh oh"), 733 rename("a/b", "a/c"), 734 ), 735 as(bob, noSync(), 736 write("a/b", "world"), 737 mkfile("a/c", "CONFLICT"), 738 reenableUpdates(), 739 lsdir("a/", m{"b$": "FILE", "c$": "FILE", crnameEsc("c", bob): "FILE"}), 740 read("a/b", "world"), 741 read("a/c", "uh oh"), 742 read(crname("a/c", bob), "CONFLICT"), 743 ), 744 as(alice, 745 lsdir("a/", m{"b$": "FILE", "c$": "FILE", crnameEsc("c", bob): "FILE"}), 746 read("a/b", "world"), 747 read("a/c", "uh oh"), 748 read(crname("a/c", bob), "CONFLICT"), 749 ), 750 ) 751 } 752 753 // alice modifies and renames (to another dir) a file that was modified 754 // by bob. 755 func TestCrConflictMergedRenameAcrossDirsModifiedFile(t *testing.T) { 756 test(t, 757 users("alice", "bob"), 758 as(alice, 759 write("a/b", "hello"), 760 ), 761 as(bob, 762 disableUpdates(), 763 ), 764 as(alice, 765 write("a/b", "world"), 766 rename("a/b", "b/c"), 767 ), 768 as(bob, noSync(), 769 write("a/b", "uh oh"), 770 reenableUpdates(), 771 lsdir("a/", m{"b$": "FILE"}), 772 read("a/b", "uh oh"), 773 lsdir("b/", m{"c$": "FILE"}), 774 read("b/c", "world"), 775 ), 776 as(alice, 777 lsdir("a/", m{"b$": "FILE"}), 778 read("a/b", "uh oh"), 779 lsdir("b/", m{"c$": "FILE"}), 780 read("b/c", "world"), 781 ), 782 ) 783 } 784 785 // alice sets the mtime on and renames a file that had its mtime set by bob. 786 func TestCrConflictMergedRenameSetMtimeFile(t *testing.T) { 787 targetMtime1 := time.Now().Add(1 * time.Minute) 788 targetMtime2 := targetMtime1.Add(1 * time.Minute) 789 test(t, 790 users("alice", "bob"), 791 as(alice, 792 write("a/b", "hello"), 793 ), 794 as(bob, 795 disableUpdates(), 796 ), 797 as(alice, 798 setmtime("a/b", targetMtime1), 799 rename("a/b", "a/c"), 800 ), 801 as(bob, noSync(), 802 setmtime("a/b", targetMtime2), 803 reenableUpdates(), 804 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 805 mtime("a/b", targetMtime2), 806 mtime("a/c", targetMtime1), 807 ), 808 as(alice, 809 lsdir("a/", m{"b$": "FILE", "c$": "FILE"}), 810 mtime("a/b", targetMtime2), 811 mtime("a/c", targetMtime1), 812 ), 813 ) 814 } 815 816 // alice sets the mtime on and renames a file that had its mtime set by bob. 817 func TestCrConflictMergedRenameAcrossDirsSetMtimeFile(t *testing.T) { 818 targetMtime1 := time.Now().Add(1 * time.Minute) 819 targetMtime2 := targetMtime1.Add(1 * time.Minute) 820 test(t, 821 users("alice", "bob"), 822 as(alice, 823 write("a/b", "hello"), 824 ), 825 as(bob, 826 disableUpdates(), 827 ), 828 as(alice, 829 setmtime("a/b", targetMtime1), 830 rename("a/b", "c"), 831 ), 832 as(bob, noSync(), 833 setmtime("a/b", targetMtime2), 834 reenableUpdates(), 835 lsdir("", m{"a$": "DIR", "c$": "FILE"}), 836 lsdir("a/", m{"b$": "FILE"}), 837 mtime("a/b", targetMtime2), 838 mtime("c", targetMtime1), 839 ), 840 as(alice, 841 lsdir("", m{"a$": "DIR", "c$": "FILE"}), 842 lsdir("a/", m{"b$": "FILE"}), 843 mtime("a/b", targetMtime2), 844 mtime("c", targetMtime1), 845 ), 846 ) 847 } 848 849 // alice and both both rename the same file, causing a copy. 850 func TestCrConflictRenameSameFile(t *testing.T) { 851 test(t, 852 users("alice", "bob"), 853 as(alice, 854 write("a/b", "hello"), 855 ), 856 as(bob, 857 disableUpdates(), 858 ), 859 as(alice, 860 rename("a/b", "a/c"), 861 ), 862 as(bob, noSync(), 863 rename("a/b", "a/d"), 864 reenableUpdates(), 865 lsdir("a/", m{"c": "FILE", "d": "FILE"}), 866 read("a/c", "hello"), 867 read("a/d", "hello"), 868 ), 869 as(alice, 870 lsdir("a/", m{"c": "FILE", "d": "FILE"}), 871 read("a/c", "hello"), 872 read("a/d", "hello"), 873 write("a/c", "world"), 874 ), 875 as(bob, 876 read("a/c", "world"), 877 read("a/d", "hello"), 878 ), 879 ) 880 } 881 882 // alice and both both rename the same executable file, causing a copy. 883 func TestCrConflictRenameSameEx(t *testing.T) { 884 test(t, 885 users("alice", "bob"), 886 as(alice, 887 write("a/b", "hello"), 888 setex("a/b", true), 889 ), 890 as(bob, 891 disableUpdates(), 892 ), 893 as(alice, 894 rename("a/b", "a/c"), 895 ), 896 as(bob, noSync(), 897 rename("a/b", "a/d"), 898 reenableUpdates(), 899 lsdir("a/", m{"c": "EXEC", "d": "EXEC"}), 900 read("a/c", "hello"), 901 read("a/d", "hello"), 902 ), 903 as(alice, 904 lsdir("a/", m{"c": "EXEC", "d": "EXEC"}), 905 read("a/c", "hello"), 906 read("a/d", "hello"), 907 write("a/c", "world"), 908 ), 909 as(bob, 910 read("a/c", "world"), 911 read("a/d", "hello"), 912 ), 913 ) 914 } 915 916 // alice and both both rename the same symlink. 917 func TestCrConflictRenameSameSymlink(t *testing.T) { 918 test(t, 919 skip("dokan", "Does not work with Dokan."), 920 users("alice", "bob"), 921 as(alice, 922 write("a/foo", "hello"), 923 link("a/b", "foo"), 924 ), 925 as(bob, 926 disableUpdates(), 927 ), 928 as(alice, 929 rename("a/b", "a/c"), 930 ), 931 as(bob, noSync(), 932 rename("a/b", "a/d"), 933 reenableUpdates(), 934 lsdir("a/", m{"foo": "FILE", "c": "SYM", "d": "SYM"}), 935 read("a/c", "hello"), 936 read("a/d", "hello"), 937 ), 938 as(alice, 939 lsdir("a/", m{"foo": "FILE", "c": "SYM", "d": "SYM"}), 940 read("a/c", "hello"), 941 read("a/d", "hello"), 942 write("a/c", "world"), 943 ), 944 as(bob, 945 read("a/c", "world"), 946 read("a/d", "world"), 947 ), 948 ) 949 } 950 951 // alice and bob both rename the same directory, causing a symlink to 952 // be created. 953 func TestCrConflictRenameSameDir(t *testing.T) { 954 test(t, 955 users("alice", "bob"), 956 as(alice, 957 write("a/b/c", "hello"), 958 ), 959 as(bob, 960 disableUpdates(), 961 ), 962 as(alice, 963 rename("a/b", "a/d"), 964 ), 965 as(bob, noSync(), 966 rename("a/b", "a/e"), 967 reenableUpdates(), 968 lsdir("a/", m{"d": "DIR", "e": "SYM"}), 969 read("a/d/c", "hello"), 970 read("a/e/c", "hello"), 971 ), 972 as(alice, 973 lsdir("a/", m{"d": "DIR", "e": "SYM"}), 974 read("a/d/c", "hello"), 975 read("a/e/c", "hello"), 976 write("a/d/f", "world"), 977 read("a/e/f", "world"), 978 ), 979 as(bob, 980 read("a/e/f", "world"), 981 ), 982 ) 983 } 984 985 // alice and bob both rename the same directory, causing a symlink to 986 // be created. 987 func TestCrConflictRenameSameDirUpward(t *testing.T) { 988 test(t, 989 users("alice", "bob"), 990 as(alice, 991 write("a/b/c/d/e/foo", "hello"), 992 ), 993 as(bob, 994 disableUpdates(), 995 ), 996 as(alice, 997 rename("a/b/c/d/e", "a/e"), 998 ), 999 as(bob, noSync(), 1000 rename("a/b/c/d/e", "a/b/c/d/f"), 1001 reenableUpdates(), 1002 lsdir("a/", m{"b": "DIR", "e": "DIR"}), 1003 lsdir("a/e", m{"foo": "FILE"}), 1004 lsdir("a/b/c/d", m{"f": "SYM"}), 1005 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1006 read("a/e/foo", "hello"), 1007 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1008 ), 1009 as(alice, 1010 lsdir("a/", m{"b": "DIR", "e": "DIR"}), 1011 lsdir("a/e", m{"foo": "FILE"}), 1012 lsdir("a/b/c/d", m{"f": "SYM"}), 1013 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1014 read("a/e/foo", "hello"), 1015 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1016 write("a/e/foo2", "world"), 1017 ), 1018 as(bob, 1019 read("a/b/c/d/f/foo2", "world"), 1020 ), 1021 ) 1022 } 1023 1024 // alice and bob both rename the same directory, causing a symlink to 1025 // be created. 1026 func TestCrConflictRenameSameDirMergedUpward(t *testing.T) { 1027 test(t, 1028 users("alice", "bob"), 1029 as(alice, 1030 write("a/b/c/d/e/foo", "hello"), 1031 ), 1032 as(bob, 1033 disableUpdates(), 1034 ), 1035 as(alice, 1036 rename("a/b/c/d/e", "a/b/c/d/f"), 1037 ), 1038 as(bob, noSync(), 1039 rename("a/b/c/d/e", "a/e"), 1040 reenableUpdates(), 1041 lsdir("a/", m{"b": "DIR", "e": "SYM"}), 1042 lsdir("a/e", m{"foo": "FILE"}), 1043 lsdir("a/b/c/d", m{"f": "DIR"}), 1044 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1045 read("a/e/foo", "hello"), 1046 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1047 ), 1048 as(alice, 1049 lsdir("a/", m{"b": "DIR", "e": "SYM"}), 1050 lsdir("a/e", m{"foo": "FILE"}), 1051 lsdir("a/b/c/d", m{"f": "DIR"}), 1052 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1053 read("a/e/foo", "hello"), 1054 lsdir("a/b/c/d/f", m{"foo": "FILE"}), 1055 write("a/e/foo2", "world"), 1056 ), 1057 as(bob, 1058 read("a/b/c/d/f/foo2", "world"), 1059 ), 1060 ) 1061 } 1062 1063 func TestCrConflictRenameSameDirDownward(t *testing.T) { 1064 test(t, 1065 users("alice", "bob"), 1066 as(alice, 1067 write("a/b/foo", "hello"), 1068 ), 1069 as(bob, 1070 disableUpdates(), 1071 ), 1072 as(alice, 1073 rename("a/b", "a/c/d/e/f"), 1074 ), 1075 as(bob, noSync(), 1076 rename("a/b", "a/g"), 1077 reenableUpdates(), 1078 lsdir("a/", m{"c": "DIR", "g": "SYM"}), 1079 lsdir("a/c/d/e/f", m{"foo": "FILE"}), 1080 lsdir("a/g", m{"foo": "FILE"}), 1081 read("a/c/d/e/f/foo", "hello"), 1082 read("a/g/foo", "hello"), 1083 ), 1084 as(alice, 1085 lsdir("a/", m{"c": "DIR", "g": "SYM"}), 1086 lsdir("a/c/d/e/f", m{"foo": "FILE"}), 1087 lsdir("a/g", m{"foo": "FILE"}), 1088 read("a/c/d/e/f/foo", "hello"), 1089 read("a/g/foo", "hello"), 1090 write("a/c/d/e/f/foo2", "world"), 1091 ), 1092 as(bob, 1093 read("a/g/foo2", "world"), 1094 ), 1095 ) 1096 } 1097 1098 func TestCrConflictRenameSameDirSideways(t *testing.T) { 1099 test(t, 1100 users("alice", "bob"), 1101 as(alice, 1102 write("a/b/c/d/foo", "hello"), 1103 ), 1104 as(bob, 1105 disableUpdates(), 1106 ), 1107 as(alice, 1108 rename("a/b/c/d", "a/e/f/g"), 1109 ), 1110 as(bob, noSync(), 1111 rename("a/b/c/d", "a/b/c/h"), 1112 reenableUpdates(), 1113 lsdir("a/e/f", m{"g": "DIR"}), 1114 lsdir("a/b/c", m{"h": "SYM"}), 1115 lsdir("a/e/f/g", m{"foo": "FILE"}), 1116 lsdir("a/b/c/h", m{"foo": "FILE"}), 1117 read("a/e/f/g/foo", "hello"), 1118 read("a/b/c/h/foo", "hello"), 1119 ), 1120 as(alice, 1121 lsdir("a/e/f", m{"g": "DIR"}), 1122 lsdir("a/b/c", m{"h": "SYM"}), 1123 lsdir("a/e/f/g", m{"foo": "FILE"}), 1124 lsdir("a/b/c/h", m{"foo": "FILE"}), 1125 read("a/e/f/g/foo", "hello"), 1126 read("a/b/c/h/foo", "hello"), 1127 write("a/e/f/g/foo2", "world"), 1128 ), 1129 as(bob, 1130 read("a/b/c/h/foo2", "world"), 1131 ), 1132 ) 1133 } 1134 1135 // bob renames an existing directory over one created by alice, twice. 1136 // TODO: it would be better if this weren't a conflict. 1137 func TestCrConflictUnmergedRenamedDirDouble(t *testing.T) { 1138 test(t, 1139 users("alice", "bob"), 1140 as(alice, 1141 write("a/b/c", "hello"), 1142 ), 1143 as(bob, 1144 disableUpdates(), 1145 ), 1146 as(alice, 1147 write("a/d/e", "world"), 1148 ), 1149 as(bob, noSync(), 1150 write("a/b/f", "uh oh"), 1151 rename("a/b", "a/d"), 1152 reenableUpdates(), 1153 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob): "DIR"}), 1154 lsdir("a/d", m{"e": "FILE"}), 1155 lsdir(crname("a/d", bob), m{"c": "FILE", "f": "FILE"}), 1156 read(crname("a/d", bob)+"/c", "hello"), 1157 read("a/d/e", "world"), 1158 read(crname("a/d", bob)+"/f", "uh oh"), 1159 ), 1160 as(alice, 1161 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob): "DIR"}), 1162 lsdir("a/d", m{"e": "FILE"}), 1163 lsdir(crname("a/d", bob), m{"c": "FILE", "f": "FILE"}), 1164 read(crname("a/d", bob)+"/c", "hello"), 1165 read("a/d/e", "world"), 1166 read(crname("a/d", bob)+"/f", "uh oh"), 1167 rm("a/d/e"), 1168 rm("a/d"), 1169 write("a/b/c", "hello"), 1170 ), 1171 as(bob, 1172 disableUpdates(), 1173 ), 1174 as(alice, 1175 write("a/d/e", "world"), 1176 ), 1177 as(bob, noSync(), 1178 write("a/b/f", "uh oh"), 1179 rename("a/b", "a/d"), 1180 reenableUpdates(), 1181 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob) + "$": "DIR", crnameEsc("d", bob) + ` \(1\)`: "DIR"}), 1182 lsdir("a/d", m{"e": "FILE"}), 1183 lsdir(crname("a/d", bob)+" (1)", m{"c": "FILE", "f": "FILE"}), 1184 read("a/d/e", "world"), 1185 ), 1186 as(alice, 1187 lsdir("a/", m{"d$": "DIR", crnameEsc("d", bob) + "$": "DIR", crnameEsc("d", bob) + ` \(1\)`: "DIR"}), 1188 lsdir("a/d", m{"e": "FILE"}), 1189 lsdir(crname("a/d", bob)+" (1)", m{"c": "FILE", "f": "FILE"}), 1190 read("a/d/e", "world"), 1191 ), 1192 ) 1193 } 1194 1195 // bob and alice both write(to the same file), 1196 func TestCrConflictWriteFileDouble(t *testing.T) { 1197 test(t, 1198 users("alice", "bob"), 1199 as(alice, 1200 mkfile("a/b", "hello"), 1201 ), 1202 as(bob, 1203 disableUpdates(), 1204 ), 1205 as(alice, 1206 write("a/b", "world"), 1207 ), 1208 as(bob, noSync(), 1209 write("a/b", "uh oh"), 1210 reenableUpdates(), 1211 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1212 read("a/b", "world"), 1213 read(crname("a/b", bob), "uh oh"), 1214 ), 1215 as(alice, 1216 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1217 read("a/b", "world"), 1218 read(crname("a/b", bob), "uh oh"), 1219 ), 1220 as(bob, 1221 disableUpdates(), 1222 ), 1223 as(alice, 1224 write("a/b", "another write"), 1225 ), 1226 as(bob, noSync(), 1227 write("a/b", "uh oh again!"), 1228 reenableUpdates(), 1229 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob) + "$": "FILE", crnameEsc("b", bob) + ` \(1\)`: "FILE"}), 1230 read("a/b", "another write"), 1231 read(crname("a/b", bob), "uh oh"), 1232 read(crname("a/b", bob)+" (1)", "uh oh again!"), 1233 ), 1234 as(alice, 1235 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob) + "$": "FILE", crnameEsc("b", bob) + ` \(1\)`: "FILE"}), 1236 read("a/b", "another write"), 1237 read(crname("a/b", bob), "uh oh"), 1238 read(crname("a/b", bob)+" (1)", "uh oh again!"), 1239 ), 1240 ) 1241 } 1242 1243 // bob and alice both write(to the same file), 1244 func TestCrConflictWriteFileDoubleWithExtensions(t *testing.T) { 1245 test(t, 1246 users("alice", "bob"), 1247 as(alice, 1248 mkfile("a/file.tar.gz", "hello"), 1249 ), 1250 as(bob, 1251 disableUpdates(), 1252 ), 1253 as(alice, 1254 write("a/file.tar.gz", "world"), 1255 ), 1256 as(bob, noSync(), 1257 write("a/file.tar.gz", "uh oh"), 1258 reenableUpdates(), 1259 lsdir("a/", m{"file.tar.gz$": "FILE", crnameEsc("file.tar.gz", bob): "FILE"}), 1260 read("a/file.tar.gz", "world"), 1261 read(crname("a/file.tar.gz", bob), "uh oh"), 1262 ), 1263 as(alice, 1264 lsdir("a/", m{"file.tar.gz$": "FILE", crnameEsc("file.tar.gz", bob): "FILE"}), 1265 read("a/file.tar.gz", "world"), 1266 read(crname("a/file.tar.gz", bob), "uh oh"), 1267 ), 1268 as(bob, 1269 disableUpdates(), 1270 ), 1271 as(alice, 1272 write("a/file.tar.gz", "another write"), 1273 ), 1274 as(bob, noSync(), 1275 write("a/file.tar.gz", "uh oh again!"), 1276 reenableUpdates(), 1277 lsdir("a/", m{"file.tar.gz$": "FILE", crnameEsc("file.tar.gz", bob) + "$": "FILE", crnameEsc("file", bob) + ` \(1\).tar.gz`: "FILE"}), 1278 read("a/file.tar.gz", "another write"), 1279 read(crname("a/file.tar.gz", bob), "uh oh"), 1280 read(crname("a/file", bob)+" (1).tar.gz", "uh oh again!"), 1281 ), 1282 as(alice, 1283 lsdir("a/", m{"file.tar.gz$": "FILE", crnameEsc("file.tar.gz", bob) + "$": "FILE", crnameEsc("file", bob) + ` \(1\).tar.gz`: "FILE"}), 1284 read("a/file.tar.gz", "another write"), 1285 read(crname("a/file.tar.gz", bob), "uh oh"), 1286 read(crname("a/file", bob)+" (1).tar.gz", "uh oh again!"), 1287 ), 1288 ) 1289 } 1290 1291 // bob causes a rename cycle with a conflict while unstaged. 1292 func TestCrRenameCycleWithConflict(t *testing.T) { 1293 test(t, 1294 users("alice", "bob"), 1295 as(alice, 1296 mkdir("a"), 1297 mkdir("a/b"), 1298 mkdir("a/c"), 1299 ), 1300 as(bob, 1301 disableUpdates(), 1302 ), 1303 as(alice, 1304 rename("a/c", "a/b/c"), 1305 ), 1306 as(bob, noSync(), 1307 rename("a/b", "a/c/b"), 1308 write("a/b", "uh oh"), 1309 reenableUpdates(), 1310 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "FILE"}), 1311 read(crname("a/b", bob), "uh oh"), 1312 lsdir("a/b/", m{"c": "DIR"}), 1313 lsdir("a/b/c", m{"b": "SYM"}), 1314 lsdir("a/b/c/b", m{"c": "DIR"}), 1315 ), 1316 as(alice, 1317 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "FILE"}), 1318 read(crname("a/b", bob), "uh oh"), 1319 lsdir("a/b/", m{"c": "DIR"}), 1320 lsdir("a/b/c", m{"b": "SYM"}), 1321 lsdir("a/b/c/b", m{"c": "DIR"}), 1322 write("a/b/d", "hello"), 1323 ), 1324 as(bob, 1325 read("a/b/c/b/d", "hello"), 1326 ), 1327 ) 1328 } 1329 1330 // bob causes a rename cycle with two conflicts while unstaged. 1331 func TestCrRenameCycleWithTwoConflicts(t *testing.T) { 1332 test(t, 1333 users("alice", "bob"), 1334 as(alice, 1335 mkdir("a"), 1336 mkdir("a/b"), 1337 mkdir("a/c"), 1338 ), 1339 as(bob, 1340 disableUpdates(), 1341 ), 1342 as(alice, 1343 rename("a/c", "a/b/c"), 1344 write("a/b/c/b", "uh oh"), 1345 ), 1346 as(bob, noSync(), 1347 rename("a/b", "a/c/b"), 1348 write("a/b", "double uh oh"), 1349 reenableUpdates(), 1350 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "FILE"}), 1351 read(crname("a/b", bob), "double uh oh"), 1352 lsdir("a/b/", m{"c": "DIR"}), 1353 lsdir("a/b/c", m{"b$": "SYM", crnameEsc("b", alice): "FILE"}), 1354 lsdir("a/b/c/b", m{"c": "DIR"}), 1355 ), 1356 as(alice, 1357 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "FILE"}), 1358 read(crname("a/b", bob), "double uh oh"), 1359 lsdir("a/b/", m{"c": "DIR"}), 1360 lsdir("a/b/c", m{"b$": "SYM", crnameEsc("b", alice): "FILE"}), 1361 lsdir("a/b/c/b", m{"c": "DIR"}), 1362 write("a/b/d", "hello"), 1363 ), 1364 as(bob, 1365 read("a/b/c/b/d", "hello"), 1366 ), 1367 ) 1368 } 1369 1370 // bob causes a rename cycle with two conflicts while unstaged. 1371 func TestCrRenameCycleWithConflictAndMergedDir(t *testing.T) { 1372 test(t, 1373 users("alice", "bob"), 1374 as(alice, 1375 mkdir("a"), 1376 mkdir("a/b"), 1377 mkdir("a/c"), 1378 ), 1379 as(bob, 1380 disableUpdates(), 1381 ), 1382 as(alice, 1383 rename("a/c", "a/b/c"), 1384 mkdir("a/b/c/b"), 1385 ), 1386 as(bob, noSync(), 1387 rename("a/b", "a/c/b"), 1388 write("a/b", "uh oh"), 1389 reenableUpdates(), 1390 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "FILE"}), 1391 read(crname("a/b", bob), "uh oh"), 1392 lsdir("a/b/", m{"c": "DIR"}), 1393 lsdir("a/b/c", m{"b$": "DIR", crnameEsc("b", bob): "SYM"}), 1394 lsdir(crname("a/b/c/b", bob), m{"c": "DIR"}), 1395 lsdir("a/b/c/b", m{}), 1396 ), 1397 as(alice, 1398 lsdir("a/", m{"b$": "DIR", crnameEsc("b", bob): "FILE"}), 1399 read(crname("a/b", bob), "uh oh"), 1400 lsdir("a/b/", m{"c": "DIR"}), 1401 lsdir("a/b/c", m{"b$": "DIR", crnameEsc("b", bob): "SYM"}), 1402 lsdir(crname("a/b/c/b", bob), m{"c": "DIR"}), 1403 lsdir("a/b/c/b", m{}), 1404 write("a/b/d", "hello"), 1405 ), 1406 as(bob, 1407 read(crname("a/b/c/b", bob)+"/d", "hello"), 1408 ), 1409 ) 1410 } 1411 1412 // alice and bob both truncate the same file to different sizes 1413 func TestCrBothTruncateFileDifferentSizes(t *testing.T) { 1414 test(t, 1415 users("alice", "bob"), 1416 as(alice, 1417 mkfile("a/b", "hello"), 1418 ), 1419 as(bob, 1420 disableUpdates(), 1421 ), 1422 as(alice, 1423 truncate("a/b", 4), 1424 ), 1425 as(bob, noSync(), 1426 truncate("a/b", 3), 1427 reenableUpdates(), 1428 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1429 read("a/b", "hell"), 1430 read(crname("a/b", bob), "hel"), 1431 ), 1432 as(alice, 1433 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1434 read("a/b", "hell"), 1435 read(crname("a/b", bob), "hel"), 1436 ), 1437 ) 1438 } 1439 1440 // alice and bob both truncate the same file to different sizes, after 1441 // truncating to the same size 1442 func TestCrBothTruncateFileDifferentSizesAfterSameSize(t *testing.T) { 1443 test(t, 1444 users("alice", "bob"), 1445 as(alice, 1446 mkfile("a/b", "hello"), 1447 ), 1448 as(bob, 1449 disableUpdates(), 1450 ), 1451 as(alice, 1452 truncate("a/b", 0), 1453 ), 1454 as(bob, noSync(), 1455 truncate("a/b", 0), 1456 truncate("a/b", 3), 1457 reenableUpdates(), 1458 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1459 read("a/b", ""), 1460 read(crname("a/b", bob), string(make([]byte, 3))), 1461 ), 1462 as(alice, 1463 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1464 read("a/b", ""), 1465 read(crname("a/b", bob), string(make([]byte, 3))), 1466 ), 1467 ) 1468 } 1469 1470 // alice and bob both set the mtime on a file 1471 func TestCrBothSetMtimeFile(t *testing.T) { 1472 targetMtime1 := time.Now().Add(1 * time.Minute) 1473 targetMtime2 := targetMtime1.Add(1 * time.Minute) 1474 test(t, 1475 users("alice", "bob"), 1476 as(alice, 1477 mkfile("a/b", "hello"), 1478 ), 1479 as(bob, 1480 disableUpdates(), 1481 ), 1482 as(alice, 1483 setmtime("a/b", targetMtime1), 1484 ), 1485 as(bob, noSync(), 1486 setmtime("a/b", targetMtime2), 1487 reenableUpdates(), 1488 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1489 mtime("a/b", targetMtime1), 1490 mtime(crname("a/b", bob), targetMtime2), 1491 ), 1492 as(alice, 1493 lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}), 1494 mtime("a/b", targetMtime1), 1495 mtime(crname("a/b", bob), targetMtime2), 1496 ), 1497 ) 1498 } 1499 1500 // alice and bob both set the mtime on a dir 1501 func TestCrBothSetMtimeDir(t *testing.T) { 1502 targetMtime1 := time.Now().Add(1 * time.Minute) 1503 targetMtime2 := targetMtime1.Add(1 * time.Minute) 1504 test(t, 1505 skip("dokan", "Dokan can't read mtimes on symlinks."), 1506 users("alice", "bob"), 1507 as(alice, 1508 mkdir("a"), 1509 ), 1510 as(bob, 1511 disableUpdates(), 1512 ), 1513 as(alice, 1514 setmtime("a", targetMtime1), 1515 ), 1516 as(bob, noSync(), 1517 setmtime("a", targetMtime2), 1518 reenableUpdates(), 1519 lsdir("", m{"a$": "DIR", crnameEsc("a", bob): "SYM"}), 1520 mtime("a", targetMtime1), 1521 mtime(crname("a", bob), targetMtime2), 1522 ), 1523 as(alice, 1524 lsdir("", m{"a$": "DIR", crnameEsc("a", bob): "SYM"}), 1525 mtime("a", targetMtime1), 1526 mtime(crname("a", bob), targetMtime2), 1527 ), 1528 ) 1529 } 1530 1531 // alice and bob both set the mtime on a dir, while bob writes a file 1532 // in the same parent directory as the mtime'd dir. Regression test 1533 // for KBFS-3813 (which was already fixed by KBFS-3770). 1534 func TestCrBothSetMtimeDirWithWrittenFile(t *testing.T) { 1535 targetMtime1 := time.Now().Add(1 * time.Minute) 1536 targetMtime2 := targetMtime1.Add(1 * time.Minute) 1537 test(t, 1538 skip("dokan", "Dokan can't read mtimes on symlinks."), 1539 users("alice", "bob"), 1540 as(alice, 1541 mkdir("a"), 1542 mkfile("b", "foo"), 1543 ), 1544 as(bob, 1545 disableUpdates(), 1546 ), 1547 as(alice, 1548 setmtime("a", targetMtime1), 1549 ), 1550 as(bob, noSync(), 1551 setmtime("a", targetMtime2), 1552 write("b", "foo2"), 1553 reenableUpdates(), 1554 lsdir("", m{"a$": "DIR", crnameEsc("a", bob): "SYM", "b$": "FILE"}), 1555 mtime("a", targetMtime1), 1556 mtime(crname("a", bob), targetMtime2), 1557 read("b", "foo2"), 1558 ), 1559 as(alice, 1560 lsdir("", m{"a$": "DIR", crnameEsc("a", bob): "SYM", "b$": "FILE"}), 1561 mtime("a", targetMtime1), 1562 mtime(crname("a", bob), targetMtime2), 1563 read("b", "foo2"), 1564 ), 1565 ) 1566 } 1567 1568 // alice and bob both create the same dir structure and make and 1569 // rename the same file in it. Regression for KBFS-2883. 1570 func TestCrBothCreateSameRenamedFileInSameNewDir(t *testing.T) { 1571 test(t, 1572 users("alice", "bob"), 1573 as(alice, 1574 mkfile("a/b", "hello"), 1575 ), 1576 as(bob, 1577 disableUpdates(), 1578 ), 1579 as(alice, 1580 mkfile("a/c/d/e", "foo"), 1581 rename("a/c/d/e", "a/c/d/f"), 1582 ), 1583 as(bob, noSync(), 1584 mkfile("a/c/d/e", "foo"), 1585 rename("a/c/d/e", "a/c/d/f"), 1586 reenableUpdates(), 1587 lsdir("a/", m{"b$": "FILE", "c$": "DIR"}), 1588 lsdir("a/c", m{"d$": "DIR"}), 1589 lsdir("a/c/d", m{"f$": "FILE", crnameEsc("f", bob): "FILE"}), 1590 read("a/c/d/f", "foo"), 1591 read(crname("a/c/d/f", bob), "foo"), 1592 ), 1593 as(alice, 1594 lsdir("a/", m{"b$": "FILE", "c$": "DIR"}), 1595 lsdir("a/c", m{"d$": "DIR"}), 1596 lsdir("a/c/d", m{"f$": "FILE", crnameEsc("f", bob): "FILE"}), 1597 read("a/c/d/f", "foo"), 1598 read(crname("a/c/d/f", bob), "foo"), 1599 ), 1600 ) 1601 }