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 }