github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/graveler/ref/resolve_ref_test.go (about) 1 package ref_test 2 3 import ( 4 "context" 5 "errors" 6 "testing" 7 "time" 8 9 "github.com/go-test/deep" 10 "github.com/treeverse/lakefs/pkg/graveler" 11 "github.com/treeverse/lakefs/pkg/graveler/ref" 12 "github.com/treeverse/lakefs/pkg/ident" 13 "github.com/treeverse/lakefs/pkg/testutil" 14 ) 15 16 func TestResolveRawRef(t *testing.T) { 17 r, _ := testRefManager(t) 18 19 ctx := context.Background() 20 repository, err := r.CreateRepository(ctx, "repo1", graveler.Repository{ 21 StorageNamespace: "s3://", 22 CreationDate: time.Now(), 23 DefaultBranchID: "main", 24 }) 25 testutil.Must(t, err) 26 27 mainBranch, err := r.GetBranch(ctx, repository, "main") 28 if err != nil { 29 t.Fatalf("Failed to get main branch information: %s", err) 30 } 31 32 ts, _ := time.Parse(time.RFC3339, "2020-12-01T15:00:00Z") 33 var previous graveler.CommitID 34 for i := 0; i < 20; i++ { 35 c := graveler.Commit{ 36 Committer: "user1", 37 Message: "message1", 38 MetaRangeID: "deadbeef123", 39 CreationDate: ts, 40 Parents: graveler.CommitParents{}, 41 Metadata: graveler.Metadata{"foo": "bar"}, 42 } 43 if previous != "" { 44 c.Parents = append(c.Parents, previous) 45 } 46 cid, err := r.AddCommit(ctx, repository, c) 47 if err != nil { 48 t.Fatalf("unexpected error: %v", err) 49 } 50 previous = cid 51 ts = ts.Add(time.Minute) 52 } 53 54 iter, err := r.Log(ctx, repository, previous, false, nil) 55 if err != nil { 56 t.Fatalf("unexpected error: %v", err) 57 } 58 59 var commitIDs []graveler.CommitID 60 for iter.Next() { 61 commit := iter.Value() 62 if commit == nil { 63 t.Fatal("Log iterator returned nil value after Next") 64 } 65 commitIDs = append(commitIDs, commit.CommitID) 66 } 67 if err := iter.Err(); err != nil { 68 t.Fatalf("unexpected error: %v", err) 69 } 70 // commit log: 71 commitLog := []graveler.CommitID{ 72 "de85cde9a3871433ed0afad67d6505aef3b3a779223916be237b44bbdc1b65ed", 73 "abd533122a68be2fe2fea4a6a5c48229560acb98331754f87d69d93fade7a497", 74 "f5d6eb69609e31016f8c89c983a0b59ee4daca07434c89ecabf927a265feb497", 75 "5376fcefd52e7a49ea24d88af06fd3f600210abd3c9fc52fadbcc2ba36b05588", 76 "0cb1b3655d48b0b068951fac1cfc276ca01623000b7aabc53f16076a8c91725d", 77 "74f7a8402e808b8f621a4f46c2138fbf51f242273f24982d235fe3ab67db4e3b", 78 "c2b8083b2ec9d30a9e6d09d4d0938ff48a67ad7bedd532ebf17808f5f199f0b0", 79 "6564419ee5290a114a353dc1bc0c4828f46eaeddfde2d6e1b9612fbf1098203d", 80 "2f9ac33733f0a0b284d97194711b3b46de9b4ff723545d0a95951668a34cff04", 81 "1c6977726cabb5549f1ff9c8ab7ee7672033c8b5b47427b4099f26103e7fb4bc", 82 "155a755e8956eebdb31d20dace8b8fd7e8eaa4f84a58f1af701757f9a8bddc4c", 83 "504956bd68f17e1a2fec4fc9e2ada276a885236dcc730d9dc99187a4bbe73900", 84 "5ed05bd6c8ee3e1fd4d1009b19c5d74b0ef918d5e2c597a4d7d88ba36f4075d2", 85 "eb0751d2da465e3f78e90b328630c360085fa8f129351379fa3b8a0ad3fc4424", 86 "daf38e9d2a32b43a07a0768e8223d06d2f3122fcf600b2eabde613c077508c73", 87 "4f4cc1feb893ed337608cff0962bc1bcde08d3bde9752b1309eea692d87c4470", 88 "b12888687d6d3956fd40767f2697f4a3cdf7230e3b86ce63711200e420041b59", 89 "2c910787d475900509fef33de2c20700baf33dae8c0abdd6ad416e73b651ab24", 90 "c634a9bdf2d2e4d819cadaeb62a0b43ced0b0398aa513ac3cf218b4dca05dcd7", 91 "fac53a04432b2e6e7185f3ac8314a874c556b2557adf3aa8d5b1df985cf96566", 92 } 93 94 if diff := deep.Equal(commitIDs, commitLog); diff != nil { 95 t.Error("Difference found on commit log", diff) 96 } 97 98 branch1CommitID := commitLog[3] 99 testutil.Must(t, r.SetBranch(ctx, repository, "branch1", graveler.Branch{ 100 CommitID: branch1CommitID, 101 StagingToken: "token1", 102 })) 103 104 branch2CommitID := commitLog[16] 105 testutil.Must(t, r.SetBranch(ctx, repository, "branch2", graveler.Branch{ 106 CommitID: branch2CommitID, 107 StagingToken: "token2", 108 })) 109 110 tagCommitID := commitLog[9] 111 testutil.Must(t, r.CreateTag(ctx, repository, "v1.0", tagCommitID)) 112 113 commitCommitID := commitLog[11] 114 115 branch3Name := string(commitLog[10])[:6] 116 branch3CommitID := commitLog[14] 117 118 testutil.Must(t, r.SetBranch(ctx, repository, graveler.BranchID(branch3Name), graveler.Branch{ 119 CommitID: branch3CommitID, 120 StagingToken: "token3", 121 })) 122 123 tag2Name := string(commitLog[6])[:10] 124 tag2CommitID := commitLog[8] 125 126 testutil.Must(t, r.CreateTag(ctx, repository, graveler.TagID(tag2Name), tag2CommitID)) 127 128 table := []struct { 129 Name string 130 Ref graveler.Ref 131 ExpectedCommitID graveler.CommitID 132 ExpectedBranchModifier graveler.ResolvedBranchModifier 133 ExpectedToken graveler.StagingToken 134 ExpectedErr error 135 }{ 136 { 137 Name: "branch_exist", 138 Ref: graveler.Ref("branch1"), 139 ExpectedBranchModifier: graveler.ResolvedBranchModifierNone, 140 ExpectedToken: "token1", 141 ExpectedCommitID: branch1CommitID, 142 }, 143 { 144 Name: "branch_doesnt_exist", 145 Ref: graveler.Ref("branch3"), 146 ExpectedErr: graveler.ErrNotFound, 147 }, 148 { 149 Name: "branch_head", 150 Ref: graveler.Ref("branch1@"), 151 ExpectedBranchModifier: graveler.ResolvedBranchModifierCommitted, 152 ExpectedCommitID: branch1CommitID, 153 }, 154 { 155 Name: "branch_invalid_head", 156 Ref: graveler.Ref("branch1@1"), 157 ExpectedErr: graveler.ErrInvalidRef, 158 }, 159 { 160 Name: "branch_invalid_head_caret1", 161 Ref: graveler.Ref("branch1@^"), 162 ExpectedErr: graveler.ErrInvalidRef, 163 }, 164 { 165 Name: "branch_invalid_head_caret2", 166 Ref: graveler.Ref("branch1^@"), 167 ExpectedErr: graveler.ErrInvalidRef, 168 }, 169 { 170 Name: "main_staging", 171 Ref: graveler.Ref("main$"), 172 ExpectedBranchModifier: graveler.ResolvedBranchModifierStaging, 173 ExpectedCommitID: mainBranch.CommitID, 174 ExpectedToken: mainBranch.StagingToken, 175 }, 176 { 177 Name: "main_committed", 178 Ref: graveler.Ref("main@"), 179 ExpectedBranchModifier: graveler.ResolvedBranchModifierCommitted, 180 ExpectedCommitID: mainBranch.CommitID, 181 }, 182 { 183 Name: "tag_exist", 184 Ref: graveler.Ref("v1.0"), 185 ExpectedCommitID: tagCommitID, 186 }, 187 { 188 Name: "tag_doesnt_exist", 189 Ref: graveler.Ref("v1.bad"), 190 ExpectedErr: graveler.ErrNotFound, 191 }, 192 { 193 Name: "commit", 194 Ref: graveler.Ref(commitCommitID), 195 ExpectedCommitID: commitCommitID, 196 }, 197 { 198 Name: "commit_prefix_good", 199 Ref: graveler.Ref(commitCommitID[:5]), 200 ExpectedCommitID: commitCommitID, 201 }, 202 { 203 Name: "branch_precedes_commit_prefix", 204 Ref: graveler.Ref(branch3Name), 205 ExpectedBranchModifier: graveler.ResolvedBranchModifierNone, 206 ExpectedToken: "token3", 207 ExpectedCommitID: branch3CommitID, 208 }, 209 { 210 Name: "tag_precedes_commit_prefix", 211 Ref: graveler.Ref(tag2Name), 212 ExpectedCommitID: tag2CommitID, 213 }, 214 { 215 Name: "commit_prefix_ambiguous", 216 Ref: graveler.Ref("5"), 217 ExpectedErr: graveler.ErrNotFound, 218 }, 219 { 220 Name: "commit_prefix_missing", 221 Ref: graveler.Ref("66666"), 222 ExpectedErr: graveler.ErrNotFound, 223 }, 224 { 225 Name: "branch_with_modifier", 226 Ref: graveler.Ref(branch1CommitID + "~2"), 227 ExpectedCommitID: commitLog[5], 228 }, 229 { 230 Name: "commit_with_modifier", 231 Ref: graveler.Ref(commitCommitID + "~2"), 232 ExpectedCommitID: commitLog[13], 233 }, 234 { 235 Name: "commit_prefix_with_modifier", 236 Ref: graveler.Ref(commitCommitID[:5] + "~2"), 237 ExpectedCommitID: commitLog[13], 238 }, 239 { 240 Name: "commit_prefix_with_modifier_too_big", 241 Ref: graveler.Ref(commitCommitID + "~200"), 242 ExpectedErr: graveler.ErrNotFound, 243 }, 244 } 245 246 for _, cas := range table { 247 t.Run(cas.Name, func(t *testing.T) { 248 rawRef, err := r.ParseRef(cas.Ref) 249 if err != nil { 250 if cas.ExpectedErr == nil || !errors.Is(err, cas.ExpectedErr) { 251 t.Fatalf("unexpected error while parse '%s': %v, expected: %v", cas.Ref, err, cas.ExpectedErr) 252 } 253 return 254 } 255 resolvedRef, err := r.ResolveRawRef(ctx, repository, rawRef) 256 if err != nil { 257 if cas.ExpectedErr == nil || !errors.Is(err, cas.ExpectedErr) { 258 t.Fatalf("unexpected error while resolve '%s': %v, expected: %v", cas.Ref, err, cas.ExpectedErr) 259 } 260 return 261 } 262 if cas.ExpectedCommitID != resolvedRef.CommitID { 263 t.Fatalf("got unexpected commit ID: '%s', expected: '%s'", 264 resolvedRef.CommitID, cas.ExpectedCommitID) 265 } 266 if cas.ExpectedToken != resolvedRef.StagingToken { 267 t.Fatalf("got unexpected staging token: '%s', expected: '%s'", 268 resolvedRef.StagingToken, cas.ExpectedToken) 269 } 270 if cas.ExpectedBranchModifier != resolvedRef.ResolvedBranchModifier { 271 t.Fatalf("got unexpected branch modifier: %d, expected: %d", 272 resolvedRef.ResolvedBranchModifier, cas.ExpectedBranchModifier) 273 } 274 }) 275 } 276 } 277 278 func TestResolveRef_SameDate(t *testing.T) { 279 r, _ := testRefManager(t) 280 ctx := context.Background() 281 repository, err := r.CreateRepository(ctx, "repo1", graveler.Repository{ 282 StorageNamespace: "s3://", 283 CreationDate: time.Now(), 284 DefaultBranchID: "main", 285 }) 286 testutil.Must(t, err) 287 288 ts, _ := time.Parse(time.RFC3339, "2020-12-01T15:00:00Z") 289 addCommit := func(message string, parents ...graveler.CommitID) graveler.CommitID { 290 c := graveler.Commit{ 291 Message: message, 292 Committer: "tester", 293 MetaRangeID: "deadbeef1", 294 CreationDate: ts, 295 Parents: graveler.CommitParents{}, 296 } 297 for _, p := range parents { 298 c.Parents = append(c.Parents, p) 299 } 300 cid, err := r.AddCommit(ctx, repository, c) 301 testutil.MustDo(t, "add commit", err) 302 return cid 303 } 304 c1 := addCommit("c1") 305 c2 := addCommit("c2", c1) 306 c3 := addCommit("c3", c1) 307 c4 := addCommit("c4", c3) 308 c5 := addCommit("c5", c4, c2) 309 310 it, err := r.Log(ctx, repository, c5, false, nil) 311 testutil.MustDo(t, "Log request", err) 312 var commitIDs []graveler.CommitID 313 for it.Next() { 314 commit := it.Value() 315 commitIDs = append(commitIDs, commit.CommitID) 316 } 317 testutil.MustDo(t, "Log complete iteration", it.Err()) 318 319 expected := []graveler.CommitID{c5, c4, c3, c2, c1} 320 if diff := deep.Equal(commitIDs, expected); diff != nil { 321 t.Fatal("Iterator over commits found diff:", diff) 322 } 323 } 324 325 func TestResolveRef_DereferenceWithGraph(t *testing.T) { 326 /* 327 This is taken from `git help rev-parse` - let's run these tests 328 329 G H I J 330 \ / \ / 331 D E F 332 \ | / \ 333 \ | / | 334 \|/ | 335 B C 336 \ / 337 \ / 338 A 339 340 A = = A^0 341 B = A^ = A^1 = A~1 342 C = = A^2 343 D = A^^ = A^1^1 = A~2 344 E = B^2 = A^^2 345 F = B^3 = A^^3 346 G = A^^^ = A^1^1^1 = A~3 347 H = D^2 = B^^2 = A^^^2 = A~2^2 348 I = F^ = B^3^ = A^^3^ 349 J = F^2 = B^3^2 = A^^3^2 350 */ 351 r, _ := testRefManager(t) 352 repository, err := r.CreateRepository(context.Background(), "repo1", graveler.Repository{ 353 StorageNamespace: "s3://", 354 CreationDate: time.Now(), 355 DefaultBranchID: "main", 356 }) 357 testutil.Must(t, err) 358 359 ts, _ := time.Parse(time.RFC3339, "2020-12-01T15:00:00Z") 360 addCommit := func(parents ...graveler.CommitID) graveler.CommitID { 361 commit := graveler.Commit{ 362 CreationDate: ts, 363 } 364 for _, p := range parents { 365 commit.Parents = append(commit.Parents, p) 366 } 367 cid, err := r.AddCommit(context.Background(), repository, commit) 368 testutil.MustDo(t, "add commit", err) 369 ts = ts.Add(time.Second) 370 return cid 371 } 372 373 G := addCommit() 374 H := addCommit() 375 I := addCommit() 376 J := addCommit() 377 D := addCommit(G, H) 378 E := addCommit() 379 F := addCommit(I, J) 380 B := addCommit(D, E, F) 381 C := addCommit(F) 382 A := addCommit(B, C) 383 384 resolve := func(base graveler.CommitID, mod string, expected graveler.CommitID) { 385 t.Helper() 386 reference := string(base) + mod 387 resolved, err := resolveRef(context.Background(), r, ident.NewHexAddressProvider(), repository, graveler.Ref(reference)) 388 if err != nil { 389 t.Fatalf("unexpected error: %v", err) 390 } 391 if resolved.CommitID != expected { 392 t.Fatalf("Ref %s got %s, expected %s", reference, resolved.CommitID, expected) 393 } 394 } 395 396 // now the tests: 397 resolve(A, "^0", A) 398 resolve(A, "^", B) 399 resolve(A, "^1", B) 400 resolve(A, "~1", B) 401 resolve(A, "^2", C) 402 resolve(A, "^^", D) 403 resolve(A, "^1^1", D) 404 resolve(A, "~2", D) 405 resolve(B, "^2", E) 406 resolve(A, "^^2", E) 407 resolve(B, "^2", E) 408 resolve(A, "^^2", E) 409 resolve(B, "^3", F) 410 resolve(A, "^^3", F) 411 resolve(A, "^^^", G) 412 resolve(A, "^1^1^1", G) 413 resolve(A, "~3", G) 414 resolve(D, "^2", H) 415 resolve(B, "^^2", H) 416 resolve(A, "^^^2", H) 417 resolve(A, "~2^2", H) 418 resolve(F, "^", I) 419 resolve(B, "^3^", I) 420 resolve(A, "^^3^", I) 421 resolve(F, "^2", J) 422 resolve(B, "^3^2", J) 423 resolve(A, "^^3^2", J) 424 } 425 426 func resolveRef(ctx context.Context, store ref.Store, addressProvider ident.AddressProvider, repository *graveler.RepositoryRecord, reference graveler.Ref) (*graveler.ResolvedRef, error) { 427 rawRef, err := ref.ParseRef(reference) 428 if err != nil { 429 return nil, err 430 } 431 return ref.ResolveRawRef(ctx, store, addressProvider, repository, rawRef) 432 }