github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/test/cr_multi_blocks_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 one conflict-free operation while a user is unstaged.
     6  
     7  package test
     8  
     9  import "testing"
    10  
    11  // bob writes a multi-block file while unmerged, no conflicts
    12  func TestCrUnmergedWriteMultiblockFile(t *testing.T) {
    13  	test(t,
    14  		blockSize(20), blockChangeSize(20*1024), users("alice", "bob"),
    15  		as(alice,
    16  			mkdir("a"),
    17  		),
    18  		as(bob,
    19  			disableUpdates(),
    20  		),
    21  		as(alice,
    22  			write("a/foo", "hello"),
    23  		),
    24  		as(bob, noSync(),
    25  			write("a/b", ntimesString(5, "0123456789")),
    26  			write("a/b", ntimesString(10, "0123456789")),
    27  			write("a/b", ntimesString(15, "0123456789")),
    28  			reenableUpdates(),
    29  			lsdir("a/", m{"b": "FILE", "foo": "FILE"}),
    30  			read("a/b", ntimesString(15, "0123456789")),
    31  			read("a/foo", "hello"),
    32  		),
    33  		as(alice,
    34  			lsdir("a/", m{"b": "FILE", "foo": "FILE"}),
    35  			read("a/b", ntimesString(15, "0123456789")),
    36  			read("a/foo", "hello"),
    37  		),
    38  	)
    39  }
    40  
    41  // bob writes a multi-block file with sequential writes while
    42  // unmerged, no conflicts
    43  func TestCrUnmergedWriteSequentialMultiblockFile(t *testing.T) {
    44  	test(t,
    45  		blockSize(20), blockChangeSize(20*1024), users("alice", "bob"),
    46  		as(alice,
    47  			mkdir("a"),
    48  		),
    49  		as(bob,
    50  			disableUpdates(),
    51  		),
    52  		as(alice,
    53  			write("a/foo", "hello"),
    54  		),
    55  		as(bob, noSync(),
    56  			write("a/b", ntimesString(5, "0123456789")),
    57  			pwriteBS("a/b", []byte(ntimesString(5, "0123456789")), 50),
    58  			pwriteBS("a/b", []byte(ntimesString(5, "0123456789")), 100),
    59  			reenableUpdates(),
    60  			lsdir("a/", m{"b": "FILE", "foo": "FILE"}),
    61  			read("a/b", ntimesString(15, "0123456789")),
    62  			read("a/foo", "hello"),
    63  		),
    64  		as(alice,
    65  			lsdir("a/", m{"b": "FILE", "foo": "FILE"}),
    66  			read("a/b", ntimesString(15, "0123456789")),
    67  			read("a/foo", "hello"),
    68  		),
    69  	)
    70  }
    71  
    72  // bob writes a multi-block file that conflicts with a file created by alice
    73  func TestCrConflictUnmergedWriteMultiblockFile(t *testing.T) {
    74  	test(t,
    75  		blockSize(20), blockChangeSize(20*1024), users("alice", "bob"),
    76  		as(alice,
    77  			mkdir("a"),
    78  		),
    79  		as(bob,
    80  			disableUpdates(),
    81  		),
    82  		as(alice,
    83  			write("a/b", "hello"),
    84  		),
    85  		as(bob, noSync(),
    86  			write("a/b", ntimesString(15, "0123456789")),
    87  			reenableUpdates(),
    88  			lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}),
    89  			read("a/b", "hello"),
    90  			read(crname("a/b", bob), ntimesString(15, "0123456789")),
    91  		),
    92  		as(alice,
    93  			lsdir("a/", m{"b$": "FILE", crnameEsc("b", bob): "FILE"}),
    94  			read("a/b", "hello"),
    95  			read(crname("a/b", bob), ntimesString(15, "0123456789")),
    96  		),
    97  	)
    98  }
    99  
   100  // alice writes a multi-block file that conflicts with a directory
   101  // created by alice
   102  func TestCrConflictMergedWriteMultiblockFile(t *testing.T) {
   103  	test(t,
   104  		blockSize(20), users("alice", "bob"),
   105  		as(alice,
   106  			mkdir("a"),
   107  		),
   108  		as(bob,
   109  			disableUpdates(),
   110  		),
   111  		as(alice,
   112  			write("a/b", ntimesString(15, "0123456789")),
   113  		),
   114  		as(bob, noSync(),
   115  			write("a/b/c", "hello"),
   116  			reenableUpdates(),
   117  			lsdir("a/", m{"b$": "DIR", crnameEsc("b", alice): "FILE"}),
   118  			read("a/b/c", "hello"),
   119  			read(crname("a/b", alice), ntimesString(15, "0123456789")),
   120  		),
   121  		as(alice,
   122  			lsdir("a/", m{"b$": "DIR", crnameEsc("b", alice): "FILE"}),
   123  			read("a/b/c", "hello"),
   124  			read(crname("a/b", alice), ntimesString(15, "0123456789")),
   125  		),
   126  	)
   127  }
   128  
   129  // bob writes a multi-block file when there's a conflict on another
   130  // file.  Regression test for KBFS-3770.
   131  func TestCrConflictWriteMultiblockFileDuringOtherConflict(t *testing.T) {
   132  	test(t,
   133  		blockSize(20), blockChangeSize(100*1024), users("alice", "bob"),
   134  		as(alice,
   135  			mkdir("a"),
   136  			write("a/b", ntimesString(15, "0123456789")),
   137  		),
   138  		as(bob,
   139  			disableUpdates(),
   140  		),
   141  		as(alice,
   142  			write("a/c", "foo"),
   143  		),
   144  		as(bob, noSync(),
   145  			write("a/c", "foo"),
   146  			pwriteBS("a/b", []byte(ntimesString(15, "9876543210")), 150),
   147  			reenableUpdates(),
   148  			lsdir("a/", m{"b$": "FILE", "c$": "FILE", crnameEsc("c", bob): "FILE"}),
   149  			read("a/b", ntimesString(15, "0123456789")+ntimesString(15, "9876543210")),
   150  			read("a/c", "foo"),
   151  			read(crname("a/c", bob), "foo"),
   152  		),
   153  		as(alice,
   154  			lsdir("a/", m{"b$": "FILE", "c$": "FILE", crnameEsc("c", bob): "FILE"}),
   155  			read("a/b", ntimesString(15, "0123456789")+ntimesString(15, "9876543210")),
   156  			read("a/c", "foo"),
   157  			read(crname("a/c", bob), "foo"),
   158  		),
   159  	)
   160  }
   161  
   162  // bob resurrects a file that was removed by alice
   163  func TestCrConflictWriteToRemovedMultiblockFile(t *testing.T) {
   164  	test(t,
   165  		blockSize(20), blockChangeSize(100*1024), users("alice", "bob"),
   166  		as(alice,
   167  			mkdir("a"),
   168  			write("a/b", ntimesString(15, "0123456789")),
   169  		),
   170  		as(bob,
   171  			disableUpdates(),
   172  		),
   173  		as(alice,
   174  			rm("a/b"),
   175  		),
   176  		as(bob, noSync(),
   177  			write("a/b", ntimesString(15, "9876543210")),
   178  			reenableUpdates(),
   179  			lsdir("a/", m{"b$": "FILE"}),
   180  			read("a/b", ntimesString(15, "9876543210")),
   181  		),
   182  		as(alice,
   183  			lsdir("a/", m{"b$": "FILE"}),
   184  			read("a/b", ntimesString(15, "9876543210")),
   185  		),
   186  	)
   187  }
   188  
   189  // bob makes a file that was removed by alice executable
   190  func TestCrConflictSetexToRemovedMultiblockFile(t *testing.T) {
   191  	test(t,
   192  		skip("dokan", "SetEx is a non-op on Dokan, thus no conflict."),
   193  		blockSize(20), users("alice", "bob"),
   194  		as(alice,
   195  			mkdir("a"),
   196  			write("a/b", ntimesString(15, "0123456789")),
   197  		),
   198  		as(bob,
   199  			disableUpdates(),
   200  		),
   201  		as(alice,
   202  			rm("a/b"),
   203  		),
   204  		as(bob, noSync(),
   205  			setex("a/b", true),
   206  			reenableUpdates(),
   207  			lsdir("a/", m{"b$": "EXEC"}),
   208  			read("a/b", ntimesString(15, "0123456789")),
   209  		),
   210  		as(alice,
   211  			lsdir("a/", m{"b$": "EXEC"}),
   212  			read("a/b", ntimesString(15, "0123456789")),
   213  		),
   214  	)
   215  }
   216  
   217  // bob moves a file that was removed by alice
   218  func TestCrConflictMoveRemovedMultiblockFile(t *testing.T) {
   219  	test(t,
   220  		blockSize(20), users("alice", "bob"),
   221  		as(alice,
   222  			mkdir("a"),
   223  			write("a/b", ntimesString(15, "0123456789")),
   224  		),
   225  		as(bob,
   226  			disableUpdates(),
   227  		),
   228  		as(alice,
   229  			rm("a/b"),
   230  		),
   231  		as(bob, noSync(),
   232  			rename("a/b", "a/c"),
   233  			reenableUpdates(),
   234  			lsdir("a/", m{"c$": "FILE"}),
   235  			read("a/c", ntimesString(15, "0123456789")),
   236  		),
   237  		as(alice,
   238  			lsdir("a/", m{"c$": "FILE"}),
   239  			read("a/c", ntimesString(15, "0123456789")),
   240  		),
   241  	)
   242  }
   243  
   244  // bob writes a multi-block file while unmerged and the block change
   245  // size is small, no conflicts.
   246  func TestCrUnmergedWriteMultiblockFileWithSmallBlockChangeSize(t *testing.T) {
   247  	test(t,
   248  		blockSize(100), blockChangeSize(5), users("alice", "bob"),
   249  		as(alice,
   250  			mkdir("a"),
   251  		),
   252  		as(bob,
   253  			disableUpdates(),
   254  		),
   255  		as(alice,
   256  			write("a/foo", "hello"),
   257  		),
   258  		as(bob, noSync(),
   259  			write("a/b", ntimesString(15, "0123456789")),
   260  			reenableUpdates(),
   261  			lsdir("a/", m{"b": "FILE", "foo": "FILE"}),
   262  			read("a/b", ntimesString(15, "0123456789")),
   263  			read("a/foo", "hello"),
   264  		),
   265  		as(alice,
   266  			lsdir("a/", m{"b": "FILE", "foo": "FILE"}),
   267  			read("a/b", ntimesString(15, "0123456789")),
   268  			read("a/foo", "hello"),
   269  		),
   270  	)
   271  }
   272  
   273  // bob moves a multi-block file, and then deletes its parents.
   274  func TestCrUnmergedMoveAndDeleteMultiblockFile(t *testing.T) {
   275  	test(t,
   276  		blockSize(20), users("alice", "bob"),
   277  		as(alice,
   278  			write("a/b/c/d", ntimesString(15, "0123456789")),
   279  		),
   280  		as(bob,
   281  			disableUpdates(),
   282  		),
   283  		as(alice,
   284  			write("foo", "bar"),
   285  		),
   286  		as(bob, noSync(),
   287  			rename("a/b/c/d", "a/b/c/e"),
   288  			rm("a/b/c/e"),
   289  			rmdir("a/b/c"),
   290  			rmdir("a/b"),
   291  			reenableUpdates(),
   292  			lsdir("a/", m{}),
   293  			read("foo", "bar"),
   294  		),
   295  		as(alice,
   296  			lsdir("a/", m{}),
   297  			read("foo", "bar"),
   298  		),
   299  	)
   300  }
   301  
   302  // alice writes a multi-block directory in separate batches, and bob reads it.
   303  func TestCrWriteMultiblockDirMerge(t *testing.T) {
   304  	test(t,
   305  		blockSize(20), users("alice", "bob"),
   306  		as(alice,
   307  			mkfile("a/b", "b"),
   308  			mkfile("a/c", "c"),
   309  		),
   310  		as(bob,
   311  			disableUpdates(),
   312  		),
   313  		as(alice,
   314  			mkfile("a/d", "d"),
   315  			mkfile("a/e", "e"),
   316  		),
   317  		as(bob, noSync(),
   318  			mkfile("a/f", "f"),
   319  			mkfile("a/g", "g"),
   320  			reenableUpdates(),
   321  			lsdir("a/", m{
   322  				"b": "FILE",
   323  				"c": "FILE",
   324  				"d": "FILE",
   325  				"e": "FILE",
   326  				"f": "FILE",
   327  				"g": "FILE",
   328  			}),
   329  			read("a/b", "b"),
   330  			read("a/c", "c"),
   331  			read("a/d", "d"),
   332  			read("a/e", "e"),
   333  			read("a/f", "f"),
   334  			read("a/g", "g"),
   335  		),
   336  		as(alice,
   337  			lsdir("a/", m{
   338  				"b": "FILE",
   339  				"c": "FILE",
   340  				"d": "FILE",
   341  				"e": "FILE",
   342  				"f": "FILE",
   343  				"g": "FILE",
   344  			}),
   345  			read("a/b", "b"),
   346  			read("a/c", "c"),
   347  			read("a/d", "d"),
   348  			read("a/e", "e"),
   349  			read("a/f", "f"),
   350  			read("a/g", "g"),
   351  		),
   352  	)
   353  }
   354  
   355  // alice writes a multi-level, multi-block directory structure.
   356  func TestCrRemoveMultilevelMultiblockDir(t *testing.T) {
   357  	test(t,
   358  		blockSize(20), users("alice", "bob"),
   359  		as(alice,
   360  			mkfile("a/b", "b"),
   361  			mkfile("a/c", "c"),
   362  			mkdir("a/d"),
   363  			mkfile("a/d/e", "e"),
   364  			mkfile("a/d/f", "f"),
   365  			mkdir("a/g"),
   366  			mkfile("a/g/h", "h"),
   367  			mkfile("a/g/i", "i"),
   368  		),
   369  		as(bob,
   370  			disableUpdates(),
   371  		),
   372  		as(alice,
   373  			mkdir("b"),
   374  		),
   375  		as(bob, noSync(),
   376  			rm("a/g/i"),
   377  			rm("a/g/h"),
   378  			rmdir("a/g"),
   379  			rm("a/d/f"),
   380  			rm("a/d/e"),
   381  			rmdir("a/d"),
   382  			rm("a/c"),
   383  			rm("a/b"),
   384  			rmdir("a"),
   385  			reenableUpdates(),
   386  			lsdir("", m{"b": "DIR"}),
   387  		),
   388  		as(alice,
   389  			lsdir("", m{"b": "DIR"}),
   390  		),
   391  	)
   392  }
   393  
   394  func TestCrDoubleResolutionMultiblock(t *testing.T) {
   395  	testCrDoubleResolution(t, 20)
   396  }