github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/test/cr_complex_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  	"testing"
    11  	"time"
    12  )
    13  
    14  // bob renames a non-conflicting file into a new directory while unstaged
    15  func TestCrUnmergedRenameIntoNewDir(t *testing.T) {
    16  	test(t,
    17  		users("alice", "bob"),
    18  		as(alice,
    19  			mkfile("a/b", "hello"),
    20  		),
    21  		as(bob,
    22  			disableUpdates(),
    23  		),
    24  		as(alice,
    25  			write("a/c", "world"),
    26  		),
    27  		as(bob, noSync(),
    28  			rename("a/b", "d/e"),
    29  			reenableUpdates(),
    30  			lsdir("a/", m{"c": "FILE"}),
    31  			lsdir("d/", m{"e": "FILE"}),
    32  			read("a/c", "world"),
    33  			read("d/e", "hello"),
    34  		),
    35  		as(alice,
    36  			lsdir("a/", m{"c": "FILE"}),
    37  			lsdir("d/", m{"e": "FILE"}),
    38  			read("a/c", "world"),
    39  			read("d/e", "hello"),
    40  		),
    41  	)
    42  }
    43  
    44  // alice renames a non-conflicting file into a new directory while
    45  // bob is unstaged.
    46  func TestCrMergedRenameIntoNewDir(t *testing.T) {
    47  	test(t,
    48  		users("alice", "bob"),
    49  		as(alice,
    50  			mkfile("a/b", "hello"),
    51  		),
    52  		as(bob,
    53  			disableUpdates(),
    54  		),
    55  		as(alice,
    56  			rename("a/b", "d/e"),
    57  		),
    58  		as(bob, noSync(),
    59  			write("a/c", "world"),
    60  			reenableUpdates(),
    61  			lsdir("a/", m{"c": "FILE"}),
    62  			lsdir("d/", m{"e": "FILE"}),
    63  			read("a/c", "world"),
    64  			read("d/e", "hello"),
    65  		),
    66  		as(alice,
    67  			lsdir("a/", m{"c": "FILE"}),
    68  			lsdir("d/", m{"e": "FILE"}),
    69  			read("a/c", "world"),
    70  			read("d/e", "hello"),
    71  		),
    72  	)
    73  }
    74  
    75  // bob causes a simple rename(cycle while unstaged),
    76  func TestCrRenameCycle(t *testing.T) {
    77  	test(t,
    78  		users("alice", "bob"),
    79  		as(alice,
    80  			mkdir("a"),
    81  			mkdir("b"),
    82  		),
    83  		as(bob,
    84  			disableUpdates(),
    85  		),
    86  		as(alice,
    87  			rename("b", "a/b"),
    88  		),
    89  		as(bob, noSync(),
    90  			rename("a", "b/a"),
    91  			reenableUpdates(),
    92  			lsdir("a/", m{"b": "DIR"}),
    93  			lsdir("a/b/", m{"a": "SYM"}),
    94  			lsdir("a/b/a", m{"b": "DIR"}),
    95  		),
    96  		as(alice,
    97  			lsdir("a/", m{"b": "DIR"}),
    98  			lsdir("a/b/", m{"a": "SYM"}),
    99  			lsdir("a/b/a", m{"b": "DIR"}),
   100  			write("a/c", "hello"),
   101  		),
   102  		as(bob,
   103  			read("a/b/a/c", "hello"),
   104  		),
   105  	)
   106  }
   107  
   108  // bob causes a complicated rename(cycle while unstaged),
   109  func TestCrComplexRenameCycle(t *testing.T) {
   110  	test(t,
   111  		users("alice", "bob"),
   112  		as(alice,
   113  			mkdir("a"),
   114  			mkdir("b"),
   115  		),
   116  		as(bob,
   117  			disableUpdates(),
   118  		),
   119  		as(alice,
   120  			rename("b", "a/b"),
   121  		),
   122  		as(bob, noSync(),
   123  			mkdir("b/c"),
   124  			rename("a", "b/c/a"),
   125  			reenableUpdates(),
   126  			lsdir("a/", m{"b": "DIR"}),
   127  			lsdir("a/b/", m{"c": "DIR"}),
   128  			lsdir("a/b/c", m{"a": "SYM"}),
   129  			lsdir("a/b/c/a", m{"b": "DIR"}),
   130  		),
   131  		as(alice,
   132  			lsdir("a/", m{"b": "DIR"}),
   133  			lsdir("a/b/", m{"c": "DIR"}),
   134  			lsdir("a/b/c", m{"a": "SYM"}),
   135  			lsdir("a/b/c/a", m{"b": "DIR"}),
   136  			write("a/d", "hello"),
   137  		),
   138  		as(bob,
   139  			read("a/b/c/a/d", "hello"),
   140  		),
   141  	)
   142  }
   143  
   144  // bob causes a complicated and large rename(cycle while unstaged),
   145  func TestCrComplexLargeRenameCycle(t *testing.T) {
   146  	test(t,
   147  		users("alice", "bob"),
   148  		as(alice,
   149  			mkdir("a/b/c"),
   150  			mkdir("d/e/f"),
   151  		),
   152  		as(bob,
   153  			disableUpdates(),
   154  		),
   155  		as(alice,
   156  			rename("d", "a/b/c/d"),
   157  		),
   158  		as(bob, noSync(),
   159  			mkdir("d/e/f/g/h/i"),
   160  			rename("a", "d/e/f/g/h/i/a"),
   161  			reenableUpdates(),
   162  			lsdir("a/b/c/d/e/f/g/h/i", m{"a": "SYM"}),
   163  			lsdir("a/b/c/d/e/f/g/h/i/a", m{"b": "DIR"}),
   164  		),
   165  		as(alice,
   166  			lsdir("a/b/c/d/e/f/g/h/i", m{"a": "SYM"}),
   167  			lsdir("a/b/c/d/e/f/g/h/i/a", m{"b": "DIR"}),
   168  			write("a/j", "hello"),
   169  		),
   170  		as(bob,
   171  			read("a/b/c/d/e/f/g/h/i/a/j", "hello"),
   172  		),
   173  	)
   174  }
   175  
   176  // bob and alice do a lot of complex renames cycle while unstaged
   177  func TestCrComplexRenameNoCycle(t *testing.T) {
   178  	test(t,
   179  		users("alice", "bob"),
   180  		as(alice,
   181  			mkdir("a/b/c/d/e/f/g"),
   182  		),
   183  		as(bob,
   184  			disableUpdates(),
   185  		),
   186  		as(alice,
   187  			rename("a/b/c/d/e/f", "f"),
   188  			rename("a/b/c/d", "f/g/d"),
   189  			rename("a/b", "f/g/d/e/b"),
   190  		),
   191  		as(bob, noSync(),
   192  			rename("a/b/c/d/e/f/g", "g"),
   193  			rename("a/b/c/d/e", "g/e"),
   194  			rename("a/b/c", "g/e/f/c"),
   195  			rename("a", "g/e/f/c/d/a"),
   196  			reenableUpdates(),
   197  			lsdir("f", m{"c": "DIR"}),
   198  			lsdir("f/c", m{}),
   199  			lsdir("g", m{"e": "DIR", "d": "DIR"}),
   200  			lsdir("g/e", m{"b": "DIR"}),
   201  			lsdir("g/e/b", m{}),
   202  			lsdir("g/d", m{"a": "DIR"}),
   203  		),
   204  		as(alice,
   205  			lsdir("f", m{"c": "DIR"}),
   206  			lsdir("f/c", m{}),
   207  			lsdir("g", m{"e": "DIR", "d": "DIR"}),
   208  			lsdir("g/e", m{"b": "DIR"}),
   209  			lsdir("g/e/b", m{}),
   210  			lsdir("g/d", m{"a": "DIR"}),
   211  		),
   212  	)
   213  }
   214  
   215  // bob renames a file while unmerged, at the same time alice writes to it
   216  func TestCrUnmergedRenameWithParallelWrite(t *testing.T) {
   217  	test(t,
   218  		users("alice", "bob"),
   219  		as(alice,
   220  			mkdir("a"),
   221  			mkdir("b"),
   222  			write("a/foo", "hello"),
   223  		),
   224  		as(bob,
   225  			disableUpdates(),
   226  		),
   227  		as(alice,
   228  			write("a/foo", "goodbye"),
   229  		),
   230  		as(bob, noSync(),
   231  			rename("a/foo", "b/bar"),
   232  			reenableUpdates(),
   233  			lsdir("a", m{}),
   234  			lsdir("b", m{"bar": "FILE"}),
   235  			read("b/bar", "goodbye"),
   236  		),
   237  		as(alice,
   238  			lsdir("a", m{}),
   239  			lsdir("b", m{"bar": "FILE"}),
   240  			read("b/bar", "goodbye"),
   241  		),
   242  	)
   243  }
   244  
   245  // bob makes a non-conflicting file executable while alice writes to it
   246  func TestCrUnmergedSetexParallelWrite(t *testing.T) {
   247  	test(t,
   248  		users("alice", "bob"),
   249  		as(alice,
   250  			mkfile("a/b", "hello"),
   251  		),
   252  		as(bob,
   253  			disableUpdates(),
   254  		),
   255  		as(alice,
   256  			write("a/b", "goodbye"),
   257  		),
   258  		as(bob, noSync(),
   259  			setex("a/b", true),
   260  			reenableUpdates(),
   261  			lsdir("a/", m{"b": "EXEC"}),
   262  			read("a/b", "goodbye"),
   263  		),
   264  		as(alice,
   265  			lsdir("a/", m{"b": "EXEC"}),
   266  			read("a/b", "goodbye"),
   267  		),
   268  	)
   269  }
   270  
   271  // alice makes a non-conflicting file executable while bob writes to it
   272  func TestCrMergedSetexParallelWrite(t *testing.T) {
   273  	test(t,
   274  		users("alice", "bob"),
   275  		as(alice,
   276  			mkfile("a/b", "hello"),
   277  		),
   278  		as(bob,
   279  			disableUpdates(),
   280  		),
   281  		as(alice,
   282  			setex("a/b", true),
   283  		),
   284  		as(bob, noSync(),
   285  			write("a/b", "goodbye"),
   286  			reenableUpdates(),
   287  			lsdir("a/", m{"b": "EXEC"}),
   288  			read("a/b", "goodbye"),
   289  		),
   290  		as(alice,
   291  			lsdir("a/", m{"b": "EXEC"}),
   292  			read("a/b", "goodbye"),
   293  		),
   294  	)
   295  }
   296  
   297  // bob writes to a file while alice removes it
   298  func TestCrUnmergedWriteToRemovedFile(t *testing.T) {
   299  	test(t,
   300  		users("alice", "bob"),
   301  		as(alice,
   302  			mkfile("a/b", "hello"),
   303  		),
   304  		as(bob,
   305  			disableUpdates(),
   306  		),
   307  		as(alice,
   308  			rm("a/b"),
   309  		),
   310  		as(bob, noSync(),
   311  			write("a/b", "goodbye"),
   312  			reenableUpdates(),
   313  			lsdir("a/", m{"b": "FILE"}),
   314  			read("a/b", "goodbye"),
   315  		),
   316  		as(alice,
   317  			lsdir("a/", m{"b": "FILE"}),
   318  			read("a/b", "goodbye"),
   319  		),
   320  	)
   321  }
   322  
   323  // bob writes to a file while alice renamed then removes it
   324  func TestCrUnmergedWriteToRenamedAndRemovedFile(t *testing.T) {
   325  	test(t,
   326  		users("alice", "bob"),
   327  		as(alice,
   328  			mkfile("a/b/c", "hello"),
   329  		),
   330  		as(bob,
   331  			disableUpdates(),
   332  		),
   333  		as(alice,
   334  			mkdir("d"),
   335  			rename("a/b/c", "d/c"),
   336  			rm("d/c"),
   337  		),
   338  		as(bob, noSync(),
   339  			write("a/b/c", "goodbye"),
   340  			reenableUpdates(),
   341  			lsdir("", m{"a": "DIR", "d": "DIR"}),
   342  			lsdir("a/", m{"b": "DIR"}),
   343  			lsdir("a/b/", m{"c": "FILE"}),
   344  			read("a/b/c", "goodbye"),
   345  			lsdir("d/", m{}),
   346  		),
   347  		as(alice,
   348  			lsdir("", m{"a": "DIR", "d": "DIR"}),
   349  			lsdir("a/", m{"b": "DIR"}),
   350  			lsdir("a/b/", m{"c": "FILE"}),
   351  			read("a/b/c", "goodbye"),
   352  			lsdir("d/", m{}),
   353  		),
   354  	)
   355  }
   356  
   357  // bob removes a file while alice writes to it
   358  func TestCrMergedWriteToRemovedFile(t *testing.T) {
   359  	test(t,
   360  		users("alice", "bob"),
   361  		as(alice,
   362  			mkfile("a/b", "hello"),
   363  		),
   364  		as(bob,
   365  			disableUpdates(),
   366  		),
   367  		as(alice,
   368  			write("a/b", "goodbye"),
   369  		),
   370  		as(bob, noSync(),
   371  			rm("a/b"),
   372  			reenableUpdates(),
   373  			lsdir("a/", m{"b": "FILE"}),
   374  			read("a/b", "goodbye"),
   375  		),
   376  		as(alice,
   377  			lsdir("a/", m{"b": "FILE"}),
   378  			read("a/b", "goodbye"),
   379  		),
   380  	)
   381  }
   382  
   383  // bob writes to a file to a directory that alice removes
   384  func TestCrUnmergedCreateInRemovedDir(t *testing.T) {
   385  	test(t,
   386  		users("alice", "bob"),
   387  		as(alice,
   388  			mkfile("a/b/c/d/e", "hello"),
   389  		),
   390  		as(bob,
   391  			disableUpdates(),
   392  		),
   393  		as(alice,
   394  			rm("a/b/c/d/e"),
   395  			rmdir("a/b/c/d"),
   396  			rmdir("a/b/c"),
   397  			rmdir("a/b"),
   398  		),
   399  		as(bob, noSync(),
   400  			write("a/b/c/d/f", "goodbye"),
   401  			reenableUpdates(),
   402  			lsdir("a/b/c/d", m{"f": "FILE"}),
   403  			read("a/b/c/d/f", "goodbye"),
   404  		),
   405  		as(alice,
   406  			lsdir("a/b/c/d", m{"f": "FILE"}),
   407  			read("a/b/c/d/f", "goodbye"),
   408  		),
   409  	)
   410  }
   411  
   412  // alice writes to a file to a directory that bob removes
   413  func TestCrMergedCreateInRemovedDir(t *testing.T) {
   414  	test(t,
   415  		users("alice", "bob"),
   416  		as(alice,
   417  			mkfile("a/b/c/d/e", "hello"),
   418  		),
   419  		as(bob,
   420  			disableUpdates(),
   421  		),
   422  		as(alice,
   423  			write("a/b/c/d/f", "goodbye"),
   424  		),
   425  		as(bob, noSync(),
   426  			rm("a/b/c/d/e"),
   427  			rmdir("a/b/c/d"),
   428  			rmdir("a/b/c"),
   429  			rmdir("a/b"),
   430  			reenableUpdates(),
   431  			lsdir("a/b/c/d", m{"f": "FILE"}),
   432  			read("a/b/c/d/f", "goodbye"),
   433  		),
   434  		as(alice,
   435  			lsdir("a/b/c/d", m{"f": "FILE"}),
   436  			read("a/b/c/d/f", "goodbye"),
   437  		),
   438  	)
   439  }
   440  
   441  // bob writes a file while unmerged, at the same time alice renames it
   442  func TestCrMergedRenameWithParallelWrite(t *testing.T) {
   443  	test(t,
   444  		users("alice", "bob"),
   445  		as(alice,
   446  			mkdir("a"),
   447  			mkdir("b"),
   448  			write("a/foo", "hello"),
   449  		),
   450  		as(bob,
   451  			disableUpdates(),
   452  		),
   453  		as(alice,
   454  			rename("a/foo", "b/bar"),
   455  		),
   456  		as(bob, noSync(),
   457  			write("a/foo", "goodbye"),
   458  			reenableUpdates(),
   459  			lsdir("a", m{}),
   460  			lsdir("b", m{"bar": "FILE"}),
   461  			read("b/bar", "goodbye"),
   462  		),
   463  		as(alice,
   464  			lsdir("a", m{}),
   465  			lsdir("b", m{"bar": "FILE"}),
   466  			read("b/bar", "goodbye"),
   467  		),
   468  	)
   469  }
   470  
   471  // bob has two back-to-back resolutions
   472  func testCrDoubleResolution(t *testing.T, bSize int64) {
   473  	test(t, blockSize(bSize),
   474  		users("alice", "bob"),
   475  		as(alice,
   476  			mkdir("a/b"),
   477  		),
   478  		as(bob,
   479  			disableUpdates(),
   480  		),
   481  		as(alice,
   482  			write("a/b/c", "hello"),
   483  		),
   484  		as(bob, noSync(),
   485  			write("a/b/d", "goodbye"),
   486  			reenableUpdates(),
   487  			lsdir("a", m{"b": "DIR"}),
   488  			lsdir("a/b", m{"c": "FILE", "d": "FILE"}),
   489  			read("a/b/c", "hello"),
   490  			read("a/b/d", "goodbye"),
   491  		),
   492  		as(alice,
   493  			lsdir("a", m{"b": "DIR"}),
   494  			lsdir("a/b", m{"c": "FILE", "d": "FILE"}),
   495  			read("a/b/c", "hello"),
   496  			read("a/b/d", "goodbye"),
   497  			// Make a few more revisions
   498  			write("a/b/e", "hello"),
   499  			write("a/b/f", "goodbye"),
   500  		),
   501  		as(bob,
   502  			read("a/b/e", "hello"),
   503  			read("a/b/f", "goodbye"),
   504  			disableUpdates(),
   505  		),
   506  		as(alice,
   507  			rm("a/b/f"),
   508  		),
   509  		as(bob, noSync(),
   510  			rm("a/b/e"),
   511  			reenableUpdates(),
   512  			lsdir("a", m{"b": "DIR"}),
   513  			lsdir("a/b", m{"c": "FILE", "d": "FILE"}),
   514  			read("a/b/c", "hello"),
   515  			read("a/b/d", "goodbye"),
   516  		),
   517  		as(alice,
   518  			lsdir("a", m{"b": "DIR"}),
   519  			lsdir("a/b", m{"c": "FILE", "d": "FILE"}),
   520  			read("a/b/c", "hello"),
   521  			read("a/b/d", "goodbye"),
   522  		),
   523  	)
   524  }
   525  
   526  func TestCrDoubleResolution(t *testing.T) {
   527  	testCrDoubleResolution(t, 0)
   528  }
   529  
   530  // Charlie has a resolution that touches a subdirectory that has been
   531  // deleted in Bob's resolution.
   532  func TestCrDoubleResolutionRmTree(t *testing.T) {
   533  	test(t,
   534  		users("alice", "bob", "charlie"),
   535  		as(alice,
   536  			write("a/b/c/d/e", "test1"),
   537  			write("a/b/c/d/f", "test2"),
   538  		),
   539  		as(bob,
   540  			disableUpdates(),
   541  		),
   542  		as(charlie,
   543  			disableUpdates(),
   544  		),
   545  		as(alice,
   546  			write("g", "hello"),
   547  		),
   548  		as(bob, noSync(),
   549  			// Remove a tree of files.
   550  			rm("a/b/c/d/e"),
   551  			rm("a/b/c/d/f"),
   552  			rm("a/b/c/d"),
   553  			rm("a/b/c"),
   554  			reenableUpdates(),
   555  			lsdir("", m{"a": "DIR", "g": "FILE"}),
   556  			lsdir("a", m{"b": "DIR"}),
   557  			lsdir("a/b", m{}),
   558  			read("g", "hello"),
   559  		),
   560  		as(alice,
   561  			lsdir("", m{"a": "DIR", "g": "FILE"}),
   562  			lsdir("a", m{"b": "DIR"}),
   563  			lsdir("a/b", m{}),
   564  			read("g", "hello"),
   565  		),
   566  		as(charlie, noSync(),
   567  			// Touch a subdirectory that was removed by bob.
   568  			// Unfortunately even though these are just rmOps, they
   569  			// still re-create "c/d".  Tracking a fix for that in
   570  			// KBFS-1423.
   571  			rm("a/b/c/d/e"),
   572  			rm("a/b/c/d/f"),
   573  			reenableUpdates(),
   574  			lsdir("", m{"a": "DIR", "g": "FILE"}),
   575  			lsdir("a", m{"b": "DIR"}),
   576  			lsdir("a/b", m{"c": "DIR"}),
   577  			lsdir("a/b/c", m{"d": "DIR"}),
   578  			lsdir("a/b/c/d", m{}),
   579  			read("g", "hello"),
   580  		),
   581  		as(alice,
   582  			lsdir("", m{"a": "DIR", "g": "FILE"}),
   583  			lsdir("a", m{"b": "DIR"}),
   584  			lsdir("a/b", m{"c": "DIR"}),
   585  			lsdir("a/b/c", m{"d": "DIR"}),
   586  			lsdir("a/b/c/d", m{}),
   587  			read("g", "hello"),
   588  		),
   589  		as(bob,
   590  			lsdir("", m{"a": "DIR", "g": "FILE"}),
   591  			lsdir("a", m{"b": "DIR"}),
   592  			lsdir("a/b", m{"c": "DIR"}),
   593  			lsdir("a/b/c", m{"d": "DIR"}),
   594  			lsdir("a/b/c/d", m{}),
   595  			read("g", "hello"),
   596  		),
   597  	)
   598  }
   599  
   600  // bob makes files in a directory renamed by alice
   601  func TestCrUnmergedMakeFilesInRenamedDir(t *testing.T) {
   602  	test(t,
   603  		users("alice", "bob"),
   604  		as(alice,
   605  			mkdir("a/b"),
   606  		),
   607  		as(bob,
   608  			disableUpdates(),
   609  		),
   610  		as(alice,
   611  			rename("a/b", "b"),
   612  		),
   613  		as(bob, noSync(),
   614  			write("a/b/c", "hello"),
   615  			write("a/b/d", "goodbye"),
   616  			reenableUpdates(),
   617  			lsdir("a", m{}),
   618  			lsdir("b", m{"c": "FILE", "d": "FILE"}),
   619  			read("b/c", "hello"),
   620  			read("b/d", "goodbye"),
   621  		),
   622  		as(alice,
   623  			lsdir("a", m{}),
   624  			lsdir("b", m{"c": "FILE", "d": "FILE"}),
   625  			read("b/c", "hello"),
   626  			read("b/d", "goodbye"),
   627  		),
   628  	)
   629  }
   630  
   631  // bob makes files in a directory renamed by alice
   632  func TestCrMergedMakeFilesInRenamedDir(t *testing.T) {
   633  	test(t,
   634  		users("alice", "bob"),
   635  		as(alice,
   636  			mkdir("a/b"),
   637  		),
   638  		as(bob,
   639  			disableUpdates(),
   640  		),
   641  		as(alice,
   642  			write("a/b/c", "hello"),
   643  			write("a/b/d", "goodbye"),
   644  		),
   645  		as(bob, noSync(),
   646  			rename("a/b", "b"),
   647  			reenableUpdates(),
   648  			lsdir("a", m{}),
   649  			lsdir("b", m{"c": "FILE", "d": "FILE"}),
   650  			read("b/c", "hello"),
   651  			read("b/d", "goodbye"),
   652  		),
   653  		as(alice,
   654  			lsdir("a", m{}),
   655  			lsdir("b", m{"c": "FILE", "d": "FILE"}),
   656  			read("b/c", "hello"),
   657  			read("b/d", "goodbye"),
   658  		),
   659  	)
   660  }
   661  
   662  // bob moves and setexes a file that was written by alice
   663  func TestCrConflictMoveAndSetexWrittenFile(t *testing.T) {
   664  	test(t,
   665  		users("alice", "bob"),
   666  		as(alice,
   667  			mkdir("a"),
   668  			write("a/b", "hello"),
   669  		),
   670  		as(bob,
   671  			disableUpdates(),
   672  		),
   673  		as(alice,
   674  			write("a/b", "world"),
   675  		),
   676  		as(bob, noSync(),
   677  			rename("a/b", "a/c"),
   678  			setex("a/c", true),
   679  			reenableUpdates(),
   680  			lsdir("a/", m{"c$": "EXEC"}),
   681  			read("a/c", "world"),
   682  		),
   683  		as(alice,
   684  			lsdir("a/", m{"c$": "EXEC"}),
   685  			read("a/c", "world"),
   686  		),
   687  	)
   688  }
   689  
   690  // bob moves and setexes a file that was removed by alice
   691  func TestCrConflictMoveAndSetexRemovedFile(t *testing.T) {
   692  	test(t,
   693  		users("alice", "bob"),
   694  		as(alice,
   695  			mkdir("a"),
   696  			write("a/b", "hello"),
   697  		),
   698  		as(bob,
   699  			disableUpdates(),
   700  		),
   701  		as(alice,
   702  			rm("a/b"),
   703  		),
   704  		as(bob, noSync(),
   705  			rename("a/b", "a/c"),
   706  			setex("a/c", true),
   707  			reenableUpdates(),
   708  			lsdir("a/", m{"c$": "EXEC"}),
   709  			read("a/c", "hello"),
   710  		),
   711  		as(alice,
   712  			lsdir("a/", m{"c$": "EXEC"}),
   713  			read("a/c", "hello"),
   714  		),
   715  	)
   716  }
   717  
   718  // bob creates a directory with the same name that alice used for a
   719  // file that used to exist at that location, but bob first moved it
   720  func TestCrMergedRecreatedAndUnmergedMovedFile(t *testing.T) {
   721  	test(t,
   722  		users("alice", "bob"),
   723  		as(alice,
   724  			mkdir("a"),
   725  			write("a/b", "hello"),
   726  		),
   727  		as(bob,
   728  			disableUpdates(),
   729  		),
   730  		as(alice,
   731  			write("a/b", "world"),
   732  		),
   733  		as(bob, noSync(),
   734  			rename("a/b", "a/d/b"),
   735  			rm("a/d/b"),
   736  			write("a/d/b/c", "uh oh"),
   737  			reenableUpdates(),
   738  			lsdir("a/", m{"d$": "DIR", "b$": "FILE"}),
   739  			lsdir("a/d", m{"b$": "DIR"}),
   740  			read("a/b", "world"),
   741  			read("a/d/b/c", "uh oh"),
   742  		),
   743  		as(alice,
   744  			lsdir("a/", m{"d$": "DIR", "b$": "FILE"}),
   745  			lsdir("a/d", m{"b$": "DIR"}),
   746  			read("a/b", "world"),
   747  			read("a/d/b/c", "uh oh"),
   748  		),
   749  	)
   750  }
   751  
   752  func TestCrUnmergedCreateFileInRenamedDir(t *testing.T) {
   753  	test(t,
   754  		users("alice", "bob"),
   755  		as(alice,
   756  			mkdir("a/b"),
   757  		),
   758  		as(bob,
   759  			disableUpdates(),
   760  		),
   761  		as(alice,
   762  			write("a/c", "touch"),
   763  		),
   764  		as(bob, noSync(),
   765  			mkdir("a/d"),
   766  			rename("a/b", "a/d/e"),
   767  			write("a/d/e/f", "hello"),
   768  			reenableUpdates(),
   769  			lsdir("a/", m{"c": "FILE", "d": "DIR"}),
   770  			lsdir("a/d/", m{"e": "DIR"}),
   771  			lsdir("a/d/e", m{"f": "FILE"}),
   772  			read("a/d/e/f", "hello"),
   773  		),
   774  		as(alice,
   775  			lsdir("a/", m{"c": "FILE", "d": "DIR"}),
   776  			lsdir("a/d/", m{"e": "DIR"}),
   777  			lsdir("a/d/e", m{"f": "FILE"}),
   778  			read("a/d/e/f", "hello"),
   779  		),
   780  	)
   781  }
   782  
   783  // bob moves a file that was removed by alice
   784  func TestCrUnmergedMoveOfRemovedFile(t *testing.T) {
   785  	test(t,
   786  		users("alice", "bob"),
   787  		as(alice,
   788  			mkdir("a"),
   789  			write("a/b", "hello"),
   790  		),
   791  		as(bob,
   792  			disableUpdates(),
   793  		),
   794  		as(alice,
   795  			rm("a/b"),
   796  		),
   797  		as(bob, noSync(),
   798  			rename("a/b", "a/c"),
   799  			reenableUpdates(),
   800  			lsdir("a/", m{"c$": "FILE"}),
   801  			read("a/c", "hello"),
   802  		),
   803  		as(alice,
   804  			lsdir("a/", m{"c$": "FILE"}),
   805  			read("a/c", "hello"),
   806  		),
   807  	)
   808  }
   809  
   810  // bob makes, sets the mtime, and remove a file.  Regression test for
   811  // KBFS-1163.
   812  func TestCrUnmergedSetMtimeOfRemovedDir(t *testing.T) {
   813  	targetMtime := time.Now().Add(1 * time.Minute)
   814  	test(t,
   815  		users("alice", "bob"),
   816  		as(alice,
   817  			mkdir("a/b/c"),
   818  			mkfile("a/b/c/d", "hello"),
   819  		),
   820  		as(bob,
   821  			disableUpdates(),
   822  		),
   823  		as(alice,
   824  			rm("a/b/c/d"),
   825  			rm("a/b/c"),
   826  			rm("a/b"),
   827  			rm("a"),
   828  		),
   829  		as(bob, noSync(),
   830  			setmtime("a/b/c", targetMtime),
   831  			mkfile("e", "world"),
   832  			reenableUpdates(),
   833  			lsdir("", m{"a$": "DIR", "e$": "FILE"}),
   834  			lsdir("a", m{"b$": "DIR"}),
   835  			lsdir("a/b", m{"c$": "DIR"}),
   836  			lsdir("a/b/c", m{}),
   837  			mtime("a/b/c", targetMtime),
   838  			read("e", "world"),
   839  		),
   840  		as(alice,
   841  			lsdir("", m{"a$": "DIR", "e$": "FILE"}),
   842  			lsdir("a", m{"b$": "DIR"}),
   843  			lsdir("a/b", m{"c$": "DIR"}),
   844  			lsdir("a/b/c", m{}),
   845  			mtime("a/b/c", targetMtime),
   846  			read("e", "world"),
   847  		),
   848  	)
   849  }
   850  
   851  // bob sets the mtime of a dir that is also modified by alice, then
   852  // removes that dir.  Regression test for KBFS-1691.
   853  func TestCrUnmergedSetMtimeAndRemoveModifiedDir(t *testing.T) {
   854  	origMtime := time.Now().Add(1 * time.Minute)
   855  	targetMtime := time.Now().Add(2 * time.Minute)
   856  	test(t,
   857  		users("alice", "bob"),
   858  		as(alice,
   859  			mkdir("a/b/c"),
   860  			mkfile("a/b/c/d", "hello"),
   861  			setmtime("a/b/c", origMtime),
   862  			setmtime("a/b", origMtime),
   863  		),
   864  		as(bob,
   865  			disableUpdates(),
   866  		),
   867  		as(alice,
   868  			mkfile("a/b/c/e", "hello2"),
   869  			mkfile("a/b/f", "hello3"),
   870  			setmtime("a/b/c", origMtime),
   871  			setmtime("a/b", origMtime),
   872  		),
   873  		as(bob, noSync(),
   874  			setmtime("a/b/c", targetMtime),
   875  			setmtime("a/b", targetMtime),
   876  			rm("a/b/c/d"),
   877  			rmdir("a/b/c"),
   878  			rmdir("a/b"),
   879  			reenableUpdates(),
   880  			lsdir("", m{"a$": "DIR"}),
   881  			lsdir("a", m{"b$": "DIR"}),
   882  			lsdir("a/b", m{"c$": "DIR", "f$": "FILE"}),
   883  			mtime("a/b", origMtime),
   884  			lsdir("a/b/c", m{"e$": "FILE"}),
   885  			mtime("a/b/c", origMtime),
   886  			read("a/b/c/e", "hello2"),
   887  			read("a/b/f", "hello3"),
   888  		),
   889  		as(alice,
   890  			lsdir("", m{"a$": "DIR"}),
   891  			lsdir("a", m{"b$": "DIR"}),
   892  			lsdir("a/b", m{"c$": "DIR", "f$": "FILE"}),
   893  			mtime("a/b", origMtime),
   894  			lsdir("a/b/c", m{"e$": "FILE"}),
   895  			mtime("a/b/c", origMtime),
   896  			read("a/b/c/e", "hello2"),
   897  			read("a/b/f", "hello3"),
   898  		),
   899  	)
   900  }
   901  
   902  // bob moves and sets the mtime of a file that was written by alice
   903  func TestCrConflictMoveAndSetMtimeWrittenFile(t *testing.T) {
   904  	targetMtime := time.Now().Add(1 * time.Minute)
   905  	test(t,
   906  		users("alice", "bob"),
   907  		as(alice,
   908  			mkdir("a"),
   909  			write("a/b", "hello"),
   910  		),
   911  		as(bob,
   912  			disableUpdates(),
   913  		),
   914  		as(alice,
   915  			write("a/b", "world"),
   916  		),
   917  		as(bob, noSync(),
   918  			rename("a/b", "a/c"),
   919  			setmtime("a/c", targetMtime),
   920  			reenableUpdates(),
   921  			lsdir("a/", m{"c$": "FILE"}),
   922  			read("a/c", "world"),
   923  			mtime("a/c", targetMtime),
   924  		),
   925  		as(alice,
   926  			lsdir("a/", m{"c$": "FILE"}),
   927  			read("a/c", "world"),
   928  			mtime("a/c", targetMtime),
   929  		),
   930  	)
   931  }
   932  
   933  // bob moves and sets the mtime of a file while conflicted, and then
   934  // charlie resolves a conflict on top of bob's resolution.  This is a
   935  // regression test for KBFS-1534.
   936  func TestCrConflictWriteMoveAndSetMtimeFollowedByNewConflict(t *testing.T) {
   937  	targetMtime := time.Now().Add(1 * time.Minute)
   938  	test(t,
   939  		users("alice", "bob", "charlie"),
   940  		as(alice,
   941  			mkdir("a"),
   942  		),
   943  		as(bob,
   944  			write("a/b", "hello"),
   945  			disableUpdates(),
   946  		),
   947  		as(charlie,
   948  			disableUpdates(),
   949  		),
   950  		as(alice,
   951  			write("a/c", "hello"),
   952  		),
   953  		as(bob, noSync(),
   954  			write("a/b", "hello world"),
   955  			setmtime("a/b", targetMtime),
   956  			rename("a/b", "a/d"),
   957  			reenableUpdates(),
   958  			lsdir("a/", m{"c$": "FILE", "d$": "FILE"}),
   959  			read("a/c", "hello"),
   960  			read("a/d", "hello world"),
   961  			mtime("a/d", targetMtime),
   962  		),
   963  		as(charlie, noSync(),
   964  			write("a/e", "hello too"),
   965  			reenableUpdates(),
   966  			lsdir("a/", m{"c$": "FILE", "d$": "FILE", "e$": "FILE"}),
   967  			read("a/c", "hello"),
   968  			read("a/d", "hello world"),
   969  			mtime("a/d", targetMtime),
   970  			read("a/e", "hello too"),
   971  		),
   972  		as(alice,
   973  			lsdir("a/", m{"c$": "FILE", "d$": "FILE", "e$": "FILE"}),
   974  			read("a/c", "hello"),
   975  			read("a/d", "hello world"),
   976  			mtime("a/d", targetMtime),
   977  			read("a/e", "hello too"),
   978  		),
   979  	)
   980  }
   981  
   982  // Regression test for keybase/client#9034.
   983  func TestCrCreateFileSetmtimeRenameRemoveUnmerged(t *testing.T) {
   984  	test(t,
   985  		users("alice", "bob"),
   986  		as(alice,
   987  			mkdir("a"),
   988  			write("a/b", "hello"),
   989  		),
   990  		as(bob,
   991  			disableUpdates(),
   992  		),
   993  		as(alice,
   994  			rm("a/b"),
   995  		),
   996  		as(bob, noSync(),
   997  			mkfile("c", ""),
   998  			pwriteBSSync("c", []byte("test"), 0, false),
   999  			setmtime("c", time.Now()),
  1000  			rename("c", "d"),
  1001  			rm("d"),
  1002  			reenableUpdates(),
  1003  			lsdir("a/", m{}),
  1004  		),
  1005  		as(alice,
  1006  			lsdir("a/", m{}),
  1007  		),
  1008  	)
  1009  }
  1010  
  1011  // Regression test for keybase/client#9034.
  1012  func TestCrJournalCreateDirRenameFileRemoveUnmerged(t *testing.T) {
  1013  	test(t, journal(),
  1014  		users("alice", "bob"),
  1015  		as(alice,
  1016  			mkdir("a"),
  1017  			write("a/b", "hello"),
  1018  		),
  1019  		as(bob,
  1020  			enableJournal(),
  1021  			pauseJournal(),
  1022  			mkdir("x"),
  1023  		),
  1024  		as(alice,
  1025  			rm("a/b"),
  1026  		),
  1027  		as(bob,
  1028  			mkdir("c"),
  1029  			mkfile("c/d", ""),
  1030  			pwriteBSSync("c/d", []byte("test"), 0, false),
  1031  			rename("c/d", "c/e"),
  1032  			rm("c/e"),
  1033  		),
  1034  		as(bob,
  1035  			rmdir("c"),
  1036  		),
  1037  		as(bob,
  1038  			resumeJournal(),
  1039  			flushJournal(),
  1040  		),
  1041  		as(bob,
  1042  			lsdir("a/", m{}),
  1043  			lsdir("", m{"a$": "DIR", "x$": "DIR"}),
  1044  		),
  1045  		as(alice,
  1046  			lsdir("a/", m{}),
  1047  			lsdir("", m{"a$": "DIR", "x$": "DIR"}),
  1048  		),
  1049  	)
  1050  }
  1051  
  1052  // Regression test for KBFS-2915.
  1053  func TestCrDoubleMergedDeleteAndRecreate(t *testing.T) {
  1054  	test(t,
  1055  		users("alice", "bob"),
  1056  		as(alice,
  1057  			mkdir("a/b/c/d"),
  1058  			write("a/b/c/d/e1/f1", "f1"),
  1059  			write("a/b/c/d/e2/f2", "f2"),
  1060  		),
  1061  		as(bob,
  1062  			disableUpdates(),
  1063  		),
  1064  		as(alice,
  1065  			rm("a/b/c/d/e1/f1"),
  1066  			rm("a/b/c/d/e2/f2"),
  1067  			rmdir("a/b/c/d/e1"),
  1068  			rmdir("a/b/c/d/e2"),
  1069  			rmdir("a/b/c/d"),
  1070  			rmdir("a/b/c"),
  1071  		),
  1072  		as(bob, noSync(),
  1073  			write("a/b/c/d/e1/f1", "f1.2"),
  1074  			write("a/b/c/d/e2/f2", "f2.2"),
  1075  			reenableUpdates(),
  1076  			read("a/b/c/d/e1/f1", "f1.2"),
  1077  			read("a/b/c/d/e2/f2", "f2.2"),
  1078  		),
  1079  		as(alice,
  1080  			read("a/b/c/d/e1/f1", "f1.2"),
  1081  			read("a/b/c/d/e2/f2", "f2.2"),
  1082  		),
  1083  	)
  1084  }
  1085  
  1086  // Regression test for KBFS-3915.
  1087  func TestCrSetMtimeOnCreatedDir(t *testing.T) {
  1088  	targetMtime1 := time.Now().Add(1 * time.Minute)
  1089  	targetMtime2 := targetMtime1.Add(1 * time.Minute)
  1090  	test(t, batchSize(1),
  1091  		users("alice", "bob"),
  1092  		as(alice,
  1093  			mkdir("a"),
  1094  		),
  1095  		as(bob,
  1096  			disableUpdates(),
  1097  		),
  1098  		as(alice,
  1099  			mkdir("a/b/c"),
  1100  			setmtime("a/b", targetMtime1),
  1101  		),
  1102  		as(bob, noSync(),
  1103  			mkdir("a/b/c"),
  1104  			setmtime("a/b", targetMtime2),
  1105  			reenableUpdates(),
  1106  			mtime("a/b", targetMtime1),
  1107  			mtime(crname("a/b", bob), targetMtime2),
  1108  		),
  1109  		as(alice,
  1110  			mtime("a/b", targetMtime1),
  1111  			mtime(crname("a/b", bob), targetMtime2),
  1112  		),
  1113  	)
  1114  }
  1115  
  1116  // bob sets the mtime of a file and moves it over a file that had its
  1117  // mtime set by alice.  Regression test for HOTPOT-719.
  1118  func TestCrConflictSetMtimeOnRenamedOverFile(t *testing.T) {
  1119  	targetMtime1 := time.Now().Add(1 * time.Minute)
  1120  	targetMtime2 := time.Now().Add(2 * time.Minute)
  1121  	test(t,
  1122  		users("alice", "bob"),
  1123  		as(alice,
  1124  			mkdir("a"),
  1125  			write("a/b", "hello"),
  1126  			write("a/c", "world"),
  1127  		),
  1128  		as(bob,
  1129  			disableUpdates(),
  1130  		),
  1131  		as(alice,
  1132  			setmtime("a/b", targetMtime1),
  1133  		),
  1134  		as(bob, noSync(),
  1135  			setmtime("a/b", targetMtime1),
  1136  			write("a/c", "world2"),
  1137  			setmtime("a/c", targetMtime2),
  1138  			rename("a/c", "a/b"),
  1139  			reenableUpdates(),
  1140  			mtime("a/b", targetMtime1),
  1141  			mtime(crname("a/b", bob), targetMtime2),
  1142  			read(crname("a/b", bob), "world2"),
  1143  		),
  1144  		as(alice,
  1145  			mtime("a/b", targetMtime1),
  1146  			mtime(crname("a/b", bob), targetMtime2),
  1147  			read(crname("a/b", bob), "world2"),
  1148  		),
  1149  	)
  1150  }