github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/sharing/revisions_test.go (about)

     1  package sharing
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"unicode"
     7  
     8  	"github.com/cozy/cozy-stack/pkg/config/config"
     9  	"github.com/cozy/cozy-stack/pkg/couchdb"
    10  	"github.com/cozy/cozy-stack/pkg/couchdb/revision"
    11  	"github.com/cozy/cozy-stack/tests/testutils"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestRevsTreeGeneration(t *testing.T) {
    17  	tree := &RevsTree{Rev: "1-aaa"}
    18  	assert.Equal(t, 1, tree.Generation())
    19  	twoA := RevsTree{Rev: "2-baa"}
    20  	twoB := RevsTree{Rev: "2-bbb"}
    21  	twoB.Branches = []RevsTree{{Rev: "3-ccc"}}
    22  	tree.Branches = []RevsTree{twoA, twoB}
    23  	assert.Equal(t, 3, tree.Generation())
    24  }
    25  
    26  func TestRevsTreeFind(t *testing.T) {
    27  	tree := &RevsTree{Rev: "1-aaa"}
    28  	twoA := RevsTree{Rev: "2-baa"}
    29  	twoB := RevsTree{Rev: "2-bbb"}
    30  	three := RevsTree{Rev: "3-ccc"}
    31  	twoB.Branches = []RevsTree{three}
    32  	tree.Branches = []RevsTree{twoA, twoB}
    33  	actual, depth := tree.Find("1-aaa")
    34  	assert.Equal(t, tree, actual)
    35  	assert.Equal(t, 1, depth)
    36  	actual, depth = tree.Find("2-baa")
    37  	assert.Equal(t, &twoA, actual)
    38  	assert.Equal(t, 2, depth)
    39  	actual, depth = tree.Find("2-bbb")
    40  	assert.Equal(t, &twoB, actual)
    41  	assert.Equal(t, 2, depth)
    42  	actual, depth = tree.Find("3-ccc")
    43  	assert.Equal(t, &three, actual)
    44  	assert.Equal(t, 3, depth)
    45  	actual, _ = tree.Find("4-ddd")
    46  	assert.Equal(t, (*RevsTree)(nil), actual)
    47  }
    48  
    49  func TestRevsTreeAdd(t *testing.T) {
    50  	tree := &RevsTree{Rev: "1-aaa"}
    51  	twoA := RevsTree{Rev: "2-baa"}
    52  	twoB := RevsTree{Rev: "2-bbb"}
    53  	three := RevsTree{Rev: "3-ccc"}
    54  	twoB.Branches = []RevsTree{three}
    55  	tree.Branches = []RevsTree{twoA, twoB}
    56  	ret := tree.Add("3-caa")
    57  	assert.Equal(t, "3-caa", ret.Rev)
    58  	ret = tree.Add("4-daa")
    59  	assert.Equal(t, "4-daa", ret.Rev)
    60  	ret = tree.Add("5-eaa")
    61  	assert.Equal(t, "5-eaa", ret.Rev)
    62  	assert.Equal(t, tree.Rev, "1-aaa")
    63  	assert.Len(t, tree.Branches, 2)
    64  	sub := tree.Branches[0]
    65  	assert.Equal(t, sub.Rev, "2-baa")
    66  	assert.Len(t, sub.Branches, 1)
    67  	sub = sub.Branches[0]
    68  	assert.Equal(t, sub.Rev, "3-caa")
    69  	assert.Len(t, sub.Branches, 1)
    70  	sub = sub.Branches[0]
    71  	assert.Equal(t, sub.Rev, "4-daa")
    72  	assert.Len(t, sub.Branches, 1)
    73  	sub = sub.Branches[0]
    74  	assert.Equal(t, sub.Rev, "5-eaa")
    75  	assert.Len(t, sub.Branches, 0)
    76  	sub = tree.Branches[1]
    77  	assert.Equal(t, sub.Rev, "2-bbb")
    78  	assert.Len(t, sub.Branches, 1)
    79  	sub = sub.Branches[0]
    80  	assert.Equal(t, sub.Rev, "3-ccc")
    81  	assert.Len(t, sub.Branches, 0)
    82  
    83  	tree = &RevsTree{Rev: "2-bbb"}
    84  	ret = tree.Add("1-aaa")
    85  	assert.Equal(t, "1-aaa", ret.Rev)
    86  	assert.Equal(t, "1-aaa", tree.Rev)
    87  	require.Len(t, tree.Branches, 1)
    88  	sub = tree.Branches[0]
    89  	assert.Equal(t, "2-bbb", sub.Rev)
    90  	require.Len(t, sub.Branches, 0)
    91  
    92  	tree = &RevsTree{Rev: "2-bbb"}
    93  	ret = tree.Add("3-ccc")
    94  	assert.Equal(t, "3-ccc", ret.Rev)
    95  	ret = tree.Add("1-aaa")
    96  	assert.Equal(t, "1-aaa", ret.Rev)
    97  	assert.Equal(t, "1-aaa", tree.Rev)
    98  	require.Len(t, tree.Branches, 1)
    99  	sub = tree.Branches[0]
   100  	assert.Equal(t, "2-bbb", sub.Rev)
   101  	require.Len(t, sub.Branches, 1)
   102  	sub = sub.Branches[0]
   103  	assert.Equal(t, "3-ccc", sub.Rev)
   104  	require.Len(t, sub.Branches, 0)
   105  }
   106  
   107  func TestRevsTreeInsertAfter(t *testing.T) {
   108  	tree := &RevsTree{Rev: "1-aaa"}
   109  	twoA := RevsTree{Rev: "2-baa"}
   110  	twoB := RevsTree{Rev: "2-bbb"}
   111  	three := RevsTree{Rev: "3-ccc"}
   112  	twoB.Branches = []RevsTree{three}
   113  	tree.Branches = []RevsTree{twoA, twoB}
   114  	tree.InsertAfter("4-ddd", "3-ccc")
   115  	tree.InsertAfter("4-daa", "3-caa")
   116  	tree.InsertAfter("3-caa", "2-baa")
   117  	tree.InsertAfter("5-eaa", "4-daa")
   118  	assert.Equal(t, tree.Rev, "1-aaa")
   119  	assert.Len(t, tree.Branches, 2)
   120  	sub := tree.Branches[0]
   121  	assert.Equal(t, sub.Rev, "2-baa")
   122  	assert.Len(t, sub.Branches, 1)
   123  	sub = sub.Branches[0]
   124  	assert.Equal(t, sub.Rev, "3-caa")
   125  	assert.Len(t, sub.Branches, 1)
   126  	sub = sub.Branches[0]
   127  	assert.Equal(t, sub.Rev, "4-daa")
   128  	assert.Len(t, sub.Branches, 1)
   129  	sub = sub.Branches[0]
   130  	assert.Equal(t, sub.Rev, "5-eaa")
   131  	assert.Len(t, sub.Branches, 0)
   132  	sub = tree.Branches[1]
   133  	assert.Equal(t, sub.Rev, "2-bbb")
   134  	assert.Len(t, sub.Branches, 1)
   135  	sub = sub.Branches[0]
   136  	assert.Equal(t, sub.Rev, "3-ccc")
   137  	assert.Len(t, sub.Branches, 1)
   138  	sub = sub.Branches[0]
   139  	assert.Equal(t, sub.Rev, "4-ddd")
   140  	assert.Len(t, sub.Branches, 0)
   141  }
   142  
   143  func TestRevsTreeInsertAfterMaxDepth(t *testing.T) {
   144  	tree := &RevsTree{Rev: "1-aaa"}
   145  	parent := tree.Rev
   146  	for i := 2; i < 2*MaxDepth; i++ {
   147  		next := fmt.Sprintf("%d-bbb", i)
   148  		tree.InsertAfter(next, parent)
   149  		parent = next
   150  	}
   151  	_, depth := tree.Find(parent)
   152  	assert.Equal(t, depth, MaxDepth)
   153  }
   154  
   155  func TestRevsTreeInsertChain(t *testing.T) {
   156  	tree := &RevsTree{Rev: "1-aaa"}
   157  	twoA := RevsTree{Rev: "2-baa"}
   158  	twoB := RevsTree{Rev: "2-bbb"}
   159  	three := RevsTree{Rev: "3-ccc"}
   160  	twoB.Branches = []RevsTree{three}
   161  	tree.Branches = []RevsTree{twoA, twoB}
   162  	tree.InsertChain([]string{"2-baa", "3-caa", "4-daa"})
   163  	tree.InsertChain([]string{"5-eaa"})
   164  	tree.InsertChain([]string{"2-bbb", "3-ccc", "4-ddd"})
   165  	assert.Equal(t, tree.Rev, "1-aaa")
   166  	assert.Len(t, tree.Branches, 2)
   167  	sub := tree.Branches[0]
   168  	assert.Equal(t, sub.Rev, "2-baa")
   169  	assert.Len(t, sub.Branches, 1)
   170  	sub = sub.Branches[0]
   171  	assert.Equal(t, sub.Rev, "3-caa")
   172  	assert.Len(t, sub.Branches, 1)
   173  	sub = sub.Branches[0]
   174  	assert.Equal(t, sub.Rev, "4-daa")
   175  	assert.Len(t, sub.Branches, 1)
   176  	sub = sub.Branches[0]
   177  	assert.Equal(t, sub.Rev, "5-eaa")
   178  	assert.Len(t, sub.Branches, 0)
   179  	sub = tree.Branches[1]
   180  	assert.Equal(t, sub.Rev, "2-bbb")
   181  	assert.Len(t, sub.Branches, 1)
   182  	sub = sub.Branches[0]
   183  	assert.Equal(t, sub.Rev, "3-ccc")
   184  	assert.Len(t, sub.Branches, 1)
   185  	sub = sub.Branches[0]
   186  	assert.Equal(t, sub.Rev, "4-ddd")
   187  	assert.Len(t, sub.Branches, 0)
   188  }
   189  
   190  func TestRevsTreeInsertChainStartingBefore(t *testing.T) {
   191  	tree := &RevsTree{Rev: "2-bbb"}
   192  	three := RevsTree{Rev: "3-ccc"}
   193  	tree.Branches = []RevsTree{three}
   194  	tree.InsertChain([]string{"1-aaa", "2-bbb", "3-ccc", "4-ddd"})
   195  	assert.Equal(t, tree.Rev, "2-bbb")
   196  	assert.Len(t, tree.Branches, 1)
   197  	sub := tree.Branches[0]
   198  	assert.Equal(t, sub.Rev, "3-ccc")
   199  	assert.Len(t, sub.Branches, 1)
   200  	sub = sub.Branches[0]
   201  	assert.Equal(t, sub.Rev, "4-ddd")
   202  	assert.Len(t, sub.Branches, 0)
   203  }
   204  
   205  func TestRevsStructToChain(t *testing.T) {
   206  	input := RevsStruct{
   207  		Start: 3,
   208  		IDs:   []string{"ccc", "bbb", "aaa"},
   209  	}
   210  	chain := revsStructToChain(input)
   211  	expected := []string{"1-aaa", "2-bbb", "3-ccc"}
   212  	assert.Equal(t, expected, chain)
   213  }
   214  
   215  func TestRevsChainToStruct(t *testing.T) {
   216  	slice := []string{"2-aaa", "3-bbb", "4-ccc"}
   217  	revs := revsChainToStruct(slice)
   218  	assert.Equal(t, 4, revs.Start)
   219  	assert.Equal(t, []string{"ccc", "bbb", "aaa"}, revs.IDs)
   220  }
   221  
   222  func TestDetectConflicts(t *testing.T) {
   223  	chain := []string{"1-aaa", "2-bbb", "3-ccc"}
   224  	assert.Equal(t, NoConflict, detectConflict("1-aaa", chain))
   225  	assert.Equal(t, NoConflict, detectConflict("2-bbb", chain))
   226  	assert.Equal(t, NoConflict, detectConflict("3-ccc", chain))
   227  	assert.Equal(t, WonConflict, detectConflict("2-ddd", chain))
   228  	assert.Equal(t, WonConflict, detectConflict("3-abc", chain))
   229  	assert.Equal(t, LostConflict, detectConflict("4-eee", chain))
   230  	assert.Equal(t, LostConflict, detectConflict("3-def", chain))
   231  }
   232  
   233  func TestMixupChainToResolveConflict(t *testing.T) {
   234  	chain := []string{"1-aaa", "2-bbb", "3-ccc", "4-ddd", "5-eee"}
   235  	altered := MixupChainToResolveConflict("3-abc", chain)
   236  	expected := []string{"3-abc", "4-ddd", "5-eee"}
   237  	assert.Equal(t, expected, altered)
   238  }
   239  
   240  func TestAddMissingRevsToChain(t *testing.T) {
   241  	if testing.Short() {
   242  		t.Skip("a redis is required for this test: test skipped due to the use of --short flag")
   243  	}
   244  
   245  	config.UseTestFile(t)
   246  	testutils.NeedCouchdb(t)
   247  	setup := testutils.NewSetup(t, t.Name())
   248  	inst := setup.GetTestInstance()
   249  
   250  	doc := &couchdb.JSONDoc{
   251  		Type: "io.cozy.test",
   252  		M: map[string]interface{}{
   253  			"test": "1",
   254  		},
   255  	}
   256  	assert.NoError(t, couchdb.CreateDoc(inst, doc))
   257  	rev1 := doc.Rev()
   258  	assert.NoError(t, couchdb.UpdateDoc(inst, doc))
   259  	rev2 := doc.Rev()
   260  
   261  	tree := &RevsTree{Rev: rev1}
   262  	ref := &SharedRef{
   263  		SID:       "io.cozy.test/" + doc.ID(),
   264  		Revisions: tree,
   265  	}
   266  
   267  	chain := []string{"3-ccc", "4-ddd"}
   268  	newChain, err := addMissingRevsToChain(inst, ref, chain)
   269  	assert.NoError(t, err)
   270  	expectedChain := []string{rev2, chain[0], chain[1]}
   271  	assert.Equal(t, expectedChain, newChain)
   272  }
   273  
   274  func TestIndexerIncrementRevisions(t *testing.T) {
   275  	indexer := &sharingIndexer{
   276  		bulkRevs: &bulkRevs{
   277  			Rev: "3-bf26bb2d42b0abf6a715ccf949d8e5f4",
   278  			Revisions: RevsStruct{
   279  				Start: 3,
   280  				IDs: []string{
   281  					"bf26bb2d42b0abf6a715ccf949d8e5f4",
   282  					"031e47856210360b44db86669ee83cd1",
   283  				},
   284  			},
   285  		},
   286  	}
   287  	indexer.IncrementRevision()
   288  	assert.Equal(t, 4, indexer.bulkRevs.Revisions.Start)
   289  	gen := revision.Generation(indexer.bulkRevs.Rev)
   290  	assert.Equal(t, 4, gen)
   291  	assert.Len(t, indexer.bulkRevs.Revisions.IDs, 3)
   292  	rev := fmt.Sprintf("%d-%s", gen, indexer.bulkRevs.Revisions.IDs[0])
   293  	assert.Equal(t, indexer.bulkRevs.Rev, rev)
   294  }
   295  
   296  func TestIndexerStashRevision(t *testing.T) {
   297  	indexer := &sharingIndexer{
   298  		bulkRevs: &bulkRevs{
   299  			Rev: "4-9a8d25e7fc9834dc85a252ca8c11723d",
   300  			Revisions: RevsStruct{
   301  				Start: 4,
   302  				IDs: []string{
   303  					"9a8d25e7fc9834dc85a252ca8c11723d",
   304  					"ac12db6cd9bd8190f98b2bfed6522d1f",
   305  					"9822dfe81c0e30da3d7b4213f0dcca2a",
   306  				},
   307  			},
   308  		},
   309  	}
   310  
   311  	stash := indexer.StashRevision(false)
   312  	assert.Equal(t, "9a8d25e7fc9834dc85a252ca8c11723d", stash)
   313  	assert.Equal(t, "3-ac12db6cd9bd8190f98b2bfed6522d1f", indexer.bulkRevs.Rev)
   314  	assert.Equal(t, 3, indexer.bulkRevs.Revisions.Start)
   315  	assert.Len(t, indexer.bulkRevs.Revisions.IDs, 2)
   316  	assert.Equal(t, "ac12db6cd9bd8190f98b2bfed6522d1f", indexer.bulkRevs.Revisions.IDs[0])
   317  	assert.Equal(t, "9822dfe81c0e30da3d7b4213f0dcca2a", indexer.bulkRevs.Revisions.IDs[1])
   318  
   319  	indexer.UnstashRevision(stash)
   320  	assert.Equal(t, "4-9a8d25e7fc9834dc85a252ca8c11723d", indexer.bulkRevs.Rev)
   321  	assert.Equal(t, 4, indexer.bulkRevs.Revisions.Start)
   322  	assert.Len(t, indexer.bulkRevs.Revisions.IDs, 3)
   323  	assert.Equal(t, "9a8d25e7fc9834dc85a252ca8c11723d", indexer.bulkRevs.Revisions.IDs[0])
   324  	assert.Equal(t, "ac12db6cd9bd8190f98b2bfed6522d1f", indexer.bulkRevs.Revisions.IDs[1])
   325  	assert.Equal(t, "9822dfe81c0e30da3d7b4213f0dcca2a", indexer.bulkRevs.Revisions.IDs[2])
   326  
   327  	indexer.bulkRevs = &bulkRevs{
   328  		Rev: "2-a61b005843648f5822cc44e1e586c29c",
   329  		Revisions: RevsStruct{
   330  			Start: 2,
   331  			IDs: []string{
   332  				"a61b005843648f5822cc44e1e586c29c",
   333  				"7f0065d977dcfd49bbcd77f8630f185b",
   334  			},
   335  		},
   336  	}
   337  	stash = indexer.StashRevision(false)
   338  	assert.Empty(t, stash)
   339  	assert.Nil(t, indexer.bulkRevs)
   340  	indexer.UnstashRevision(stash)
   341  	assert.Nil(t, indexer.bulkRevs)
   342  
   343  	indexer.bulkRevs = &bulkRevs{
   344  		Rev: "2-a61b005843648f5822cc44e1e586c29c",
   345  		Revisions: RevsStruct{
   346  			Start: 2,
   347  			IDs: []string{
   348  				"a61b005843648f5822cc44e1e586c29c",
   349  			},
   350  		},
   351  	}
   352  	stash = indexer.StashRevision(true)
   353  	assert.Empty(t, stash)
   354  	assert.Nil(t, indexer.bulkRevs)
   355  	indexer.UnstashRevision(stash)
   356  	assert.Nil(t, indexer.bulkRevs)
   357  }
   358  
   359  func TestIndexerCreateBogusPrevRev(t *testing.T) {
   360  	indexer := &sharingIndexer{
   361  		bulkRevs: &bulkRevs{
   362  			Rev: "3-bf26bb2d42b0abf6a715ccf949d8e5f4",
   363  			Revisions: RevsStruct{
   364  				Start: 3,
   365  				IDs: []string{
   366  					"bf26bb2d42b0abf6a715ccf949d8e5f4",
   367  				},
   368  			},
   369  		},
   370  	}
   371  	indexer.CreateBogusPrevRev()
   372  	assert.Equal(t, 3, indexer.bulkRevs.Revisions.Start)
   373  	gen := revision.Generation(indexer.bulkRevs.Rev)
   374  	assert.Equal(t, 3, gen)
   375  	assert.Len(t, indexer.bulkRevs.Revisions.IDs, 2)
   376  	rev := fmt.Sprintf("%d-%s", gen, indexer.bulkRevs.Revisions.IDs[0])
   377  	assert.Equal(t, indexer.bulkRevs.Rev, rev)
   378  }
   379  
   380  func TestConflictID(t *testing.T) {
   381  	id := "d9dfd293577eea9f6d29d140259fa71d"
   382  	rev := "3-bf26bb2d42b0abf6a715ccf949d8e5f4"
   383  	xored := conflictID(id, rev)
   384  	for _, c := range xored {
   385  		assert.True(t, unicode.IsDigit(c) || unicode.IsLetter(c))
   386  	}
   387  }