github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/merge/merge_test.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package merge 16 17 import ( 18 "context" 19 "encoding/json" 20 "sort" 21 "testing" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 27 "github.com/dolthub/dolt/go/libraries/doltcore/conflict" 28 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 29 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb/durable" 30 "github.com/dolthub/dolt/go/libraries/doltcore/env" 31 "github.com/dolthub/dolt/go/libraries/doltcore/ref" 32 "github.com/dolthub/dolt/go/libraries/doltcore/schema" 33 "github.com/dolthub/dolt/go/libraries/doltcore/table/editor" 34 "github.com/dolthub/dolt/go/libraries/doltcore/table/editor/creation" 35 filesys2 "github.com/dolthub/dolt/go/libraries/utils/filesys" 36 "github.com/dolthub/dolt/go/libraries/utils/valutil" 37 "github.com/dolthub/dolt/go/store/datas" 38 "github.com/dolthub/dolt/go/store/pool" 39 "github.com/dolthub/dolt/go/store/prolly" 40 "github.com/dolthub/dolt/go/store/prolly/tree" 41 "github.com/dolthub/dolt/go/store/types" 42 "github.com/dolthub/dolt/go/store/val" 43 ) 44 45 const ( 46 tableName = "test-table" 47 name = "billy bob" 48 email = "bigbillieb@fake.horse" 49 50 idTag = 100 51 col1Tag = 0 52 col2Tag = 1 53 ) 54 55 var colColl = schema.NewColCollection( 56 schema.NewColumn("id", idTag, types.IntKind, true, schema.NotNullConstraint{}), 57 schema.NewColumn("col1", col1Tag, types.IntKind, false, schema.NotNullConstraint{}), 58 schema.NewColumn("col2", col2Tag, types.IntKind, false, schema.NotNullConstraint{}), 59 ) 60 var sch = schema.MustSchemaFromCols(colColl) 61 62 type rowV struct { 63 col1, col2 int 64 } 65 66 var vD = sch.GetValueDescriptor() 67 var vB = val.NewTupleBuilder(vD) 68 var syncPool = pool.NewBuffPool() 69 70 func (v rowV) value() val.Tuple { 71 vB.PutInt64(0, int64(v.col1)) 72 vB.PutInt64(1, int64(v.col2)) 73 return vB.Build(syncPool) 74 } 75 76 func (v rowV) nomsValue() types.Value { 77 return valsToTestTupleWithoutPks([]types.Value{types.Int(v.col1), types.Int(v.col2)}) 78 } 79 80 const ( 81 NoopAction ActionType = iota 82 InsertAction 83 UpdateAction 84 DeleteAction 85 ) 86 87 type ActionType int 88 89 type testRow struct { 90 key int 91 initialValue *rowV 92 leftAction, rightAction ActionType 93 leftValue, rightValue *rowV 94 conflict bool 95 expectedValue *rowV 96 } 97 98 // There are 16 cases for merges if the left and right branches don't modify primary keys. 99 // 100 // If a row exists in the ancestor commit, then left and right can perform a no-op, update, 101 // or delete => 3*3 = +9. 102 // 103 // If a row does not exist in the ancestor commit, then left and right can perform a no-op or 104 // insert => 2*2 = +4. 105 // 106 // For (update, update) there are identical updates, conflicting updates, and 107 // non-conflicting updates. => +2 108 // 109 // For (insert, insert) there are identical inserts and conflicting inserts => +1 110 // 111 // A modification of a primary key is the combination of the two base cases: 112 // First, a (delete, delete), then an (insert, insert). We omit tests for these 113 // and instead defer to the base cases. 114 115 var testRows = []testRow{ 116 // Ancestor exists 117 { 118 0, 119 &rowV{0, 0}, 120 NoopAction, 121 NoopAction, 122 nil, 123 nil, 124 false, 125 &rowV{0, 0}, 126 }, 127 { 128 1, 129 &rowV{1, 1}, 130 NoopAction, 131 UpdateAction, 132 nil, 133 &rowV{-1, -1}, 134 false, 135 &rowV{-1, -1}, 136 }, 137 { 138 2, 139 &rowV{2, 2}, 140 NoopAction, 141 DeleteAction, 142 nil, 143 nil, 144 false, 145 nil, 146 }, 147 { 148 3, 149 &rowV{3, 3}, 150 UpdateAction, 151 NoopAction, 152 &rowV{-3, -3}, 153 nil, 154 false, 155 &rowV{-3, -3}, 156 }, 157 // Identical Update 158 { 159 4, 160 &rowV{4, 4}, 161 UpdateAction, 162 UpdateAction, 163 &rowV{-4, -4}, 164 &rowV{-4, -4}, 165 false, 166 &rowV{-4, -4}, 167 }, 168 // Conflicting Update 169 { 170 5, 171 &rowV{5, 5}, 172 UpdateAction, 173 UpdateAction, 174 &rowV{-5, 5}, 175 &rowV{0, 5}, 176 true, 177 &rowV{-5, 5}, 178 }, 179 // Non-conflicting update 180 { 181 6, 182 &rowV{6, 6}, 183 UpdateAction, 184 UpdateAction, 185 &rowV{-6, 6}, 186 &rowV{6, -6}, 187 false, 188 &rowV{-6, -6}, 189 }, 190 // Non-conflicting update 2 191 { 192 62, 193 &rowV{62, 62}, 194 UpdateAction, 195 UpdateAction, 196 &rowV{-62, 62}, 197 &rowV{62, -62}, 198 false, 199 &rowV{-62, -62}, 200 }, 201 { 202 7, 203 &rowV{7, 7}, 204 UpdateAction, 205 DeleteAction, 206 &rowV{-7, -7}, 207 nil, 208 true, 209 &rowV{-7, -7}, 210 }, 211 { 212 8, 213 &rowV{8, 8}, 214 DeleteAction, 215 NoopAction, 216 nil, 217 nil, 218 false, 219 nil, 220 }, 221 { 222 9, 223 &rowV{9, 9}, 224 DeleteAction, 225 UpdateAction, 226 nil, 227 &rowV{-9, -9}, 228 true, 229 nil, 230 }, 231 { 232 10, 233 &rowV{10, 10}, 234 DeleteAction, 235 DeleteAction, 236 nil, 237 nil, 238 false, 239 nil, 240 }, 241 // Key does not exist in ancestor 242 { 243 11, 244 nil, 245 NoopAction, 246 NoopAction, 247 nil, 248 nil, 249 false, 250 nil, 251 }, 252 { 253 12, 254 nil, 255 NoopAction, 256 InsertAction, 257 nil, 258 &rowV{12, 12}, 259 false, 260 &rowV{12, 12}, 261 }, 262 { 263 13, 264 nil, 265 InsertAction, 266 NoopAction, 267 &rowV{13, 13}, 268 nil, 269 false, 270 &rowV{13, 13}, 271 }, 272 // Identical Insert 273 { 274 14, 275 nil, 276 InsertAction, 277 InsertAction, 278 &rowV{14, 14}, 279 &rowV{14, 14}, 280 false, 281 &rowV{14, 14}, 282 }, 283 // Conflicting Insert 284 { 285 15, 286 nil, 287 InsertAction, 288 InsertAction, 289 &rowV{15, 15}, 290 &rowV{15, -15}, 291 true, 292 &rowV{15, 15}, 293 }, 294 } 295 296 func TestMergeCommits(t *testing.T) { 297 if !types.IsFormat_DOLT(types.Format_Default) { 298 t.Skip() 299 } 300 301 ddb, vrw, ns, rightCommitHash, ancCommitHash, root, mergeRoot, ancRoot, expectedRows, expectedArtifacts := setupMergeTest(t) 302 defer ddb.Close() 303 merger, err := NewMerger(root, mergeRoot, ancRoot, rightCommitHash, ancCommitHash, vrw, ns) 304 if err != nil { 305 t.Fatal(err) 306 } 307 opts := editor.TestEditorOptions(vrw) 308 // TODO: stats 309 merged, _, err := merger.MergeTable(sql.NewContext(context.Background()), tableName, opts, MergeOpts{IsCherryPick: false}) 310 if err != nil { 311 t.Fatal(err) 312 } 313 314 ctx := sql.NewEmptyContext() 315 316 tbl, _, err := root.GetTable(ctx, doltdb.TableName{Name: tableName}) 317 assert.NoError(t, err) 318 sch, err := tbl.GetSchema(ctx) 319 assert.NoError(t, err) 320 expected, err := doltdb.NewTable(ctx, vrw, ns, sch, expectedRows, nil, nil) 321 assert.NoError(t, err) 322 expected, err = rebuildAllProllyIndexes(ctx, expected) 323 assert.NoError(t, err) 324 expected, err = expected.SetArtifacts(ctx, durable.ArtifactIndexFromProllyMap(expectedArtifacts)) 325 require.NoError(t, err) 326 327 mergedRows, err := merged.table.GetRowData(ctx) 328 assert.NoError(t, err) 329 330 artIdx, err := merged.table.GetArtifacts(ctx) 331 require.NoError(t, err) 332 artifacts := durable.ProllyMapFromArtifactIndex(artIdx) 333 MustEqualArtifactMap(t, expectedArtifacts, artifacts) 334 335 MustEqualProlly(t, tableName, durable.ProllyMapFromIndex(expectedRows), durable.ProllyMapFromIndex(mergedRows)) 336 337 for _, index := range sch.Indexes().AllIndexes() { 338 mergedIndexRows, err := merged.table.GetIndexRowData(ctx, index.Name()) 339 require.NoError(t, err) 340 expectedIndexRows, err := expected.GetIndexRowData(ctx, index.Name()) 341 require.NoError(t, err) 342 MustEqualProlly(t, index.Name(), durable.ProllyMapFromIndex(expectedIndexRows), durable.ProllyMapFromIndex(mergedIndexRows)) 343 } 344 345 h, err := merged.table.HashOf() 346 require.NoError(t, err) 347 eh, err := expected.HashOf() 348 require.NoError(t, err) 349 require.Equal(t, eh.String(), h.String(), "table hashes do not equal") 350 } 351 352 func TestNomsMergeCommits(t *testing.T) { 353 if types.IsFormat_DOLT(types.Format_Default) { 354 t.Skip() 355 } 356 357 vrw, ns, rightCommitHash, ancCommitHash, root, mergeRoot, ancRoot, expectedRows, expectedConflicts, expectedStats := setupNomsMergeTest(t) 358 359 merger, err := NewMerger(root, mergeRoot, ancRoot, rightCommitHash, ancCommitHash, vrw, ns) 360 if err != nil { 361 t.Fatal(err) 362 } 363 opts := editor.TestEditorOptions(vrw) 364 merged, stats, err := merger.MergeTable(sql.NewContext(context.Background()), tableName, opts, MergeOpts{IsCherryPick: false}) 365 if err != nil { 366 t.Fatal(err) 367 } 368 assert.Equal(t, expectedStats, stats, "received stats is incorrect") 369 370 tbl, _, err := root.GetTable(context.Background(), doltdb.TableName{Name: tableName}) 371 assert.NoError(t, err) 372 sch, err := tbl.GetSchema(context.Background()) 373 assert.NoError(t, err) 374 expected, err := doltdb.NewNomsTable(context.Background(), vrw, ns, sch, expectedRows, nil, nil) 375 assert.NoError(t, err) 376 expected, err = editor.RebuildAllIndexes(context.Background(), expected, editor.TestEditorOptions(vrw)) 377 assert.NoError(t, err) 378 conflictSchema := conflict.NewConflictSchema(sch, sch, sch) 379 assert.NoError(t, err) 380 expected, err = expected.SetConflicts(context.Background(), conflictSchema, durable.ConflictIndexFromNomsMap(expectedConflicts, vrw)) 381 assert.NoError(t, err) 382 383 mergedRows, err := merged.table.GetNomsRowData(context.Background()) 384 assert.NoError(t, err) 385 _, confIdx, err := merged.table.GetConflicts(context.Background()) 386 assert.NoError(t, err) 387 conflicts := durable.NomsMapFromConflictIndex(confIdx) 388 389 if !mergedRows.Equals(expectedRows) { 390 t.Error(mustString(types.EncodedValue(context.Background(), expectedRows)), "\n!=\n", mustString(types.EncodedValue(context.Background(), mergedRows))) 391 } 392 if !conflicts.Equals(expectedConflicts) { 393 t.Error(mustString(types.EncodedValue(context.Background(), expectedConflicts)), "\n!=\n", mustString(types.EncodedValue(context.Background(), conflicts))) 394 } 395 396 for _, index := range sch.Indexes().AllIndexes() { 397 mergedIndexRows, err := merged.table.GetNomsIndexRowData(context.Background(), index.Name()) 398 assert.NoError(t, err) 399 expectedIndexRows, err := expected.GetNomsIndexRowData(context.Background(), index.Name()) 400 assert.NoError(t, err) 401 assert.Equal(t, expectedRows.Len(), mergedIndexRows.Len(), "index %s incorrect row count", index.Name()) 402 assert.Truef(t, expectedIndexRows.Equals(mergedIndexRows), 403 "index %s contents incorrect.\nExpected: \n%s\nReceived: \n%s\n", index.Name(), 404 mustString(types.EncodedValue(context.Background(), expectedIndexRows)), 405 mustString(types.EncodedValue(context.Background(), mergedIndexRows))) 406 } 407 408 h, err := merged.table.HashOf() 409 assert.NoError(t, err) 410 eh, err := expected.HashOf() 411 assert.NoError(t, err) 412 assert.Equal(t, eh.String(), h.String(), "table hashes do not equal") 413 } 414 415 func sortTests(t []testRow) { 416 sort.Slice(t, func(i, j int) bool { 417 return t[i].key < t[j].key 418 }) 419 } 420 421 func setupMergeTest(t *testing.T) (*doltdb.DoltDB, types.ValueReadWriter, tree.NodeStore, doltdb.Rootish, doltdb.Rootish, doltdb.RootValue, doltdb.RootValue, doltdb.RootValue, durable.Index, prolly.ArtifactMap) { 422 ddb := mustMakeEmptyRepo(t) 423 vrw := ddb.ValueReadWriter() 424 ns := ddb.NodeStore() 425 sortTests(testRows) 426 427 var initialKVs []val.Tuple 428 var expectedKVs []val.Tuple 429 430 for _, testCase := range testRows { 431 if testCase.initialValue != nil { 432 initialKVs = append(initialKVs, key(testCase.key), testCase.initialValue.value()) 433 } 434 if testCase.expectedValue != nil { 435 expectedKVs = append(expectedKVs, key(testCase.key), testCase.expectedValue.value()) 436 } 437 } 438 439 initialRows, err := prolly.NewMapFromTuples(context.Background(), ns, kD, vD, initialKVs...) 440 require.NoError(t, err) 441 expectedRows, err := prolly.NewMapFromTuples(context.Background(), ns, kD, vD, expectedKVs...) 442 require.NoError(t, err) 443 444 leftMut := initialRows.Mutate() 445 rightMut := initialRows.Mutate() 446 for _, testCase := range testRows { 447 448 switch testCase.leftAction { 449 case NoopAction: 450 break 451 case InsertAction, UpdateAction: 452 err = leftMut.Put(context.Background(), key(testCase.key), testCase.leftValue.value()) 453 require.NoError(t, err) 454 case DeleteAction: 455 err = leftMut.Delete(context.Background(), key(testCase.key)) 456 require.NoError(t, err) 457 } 458 459 switch testCase.rightAction { 460 case NoopAction: 461 break 462 case InsertAction, UpdateAction: 463 err = rightMut.Put(context.Background(), key(testCase.key), testCase.rightValue.value()) 464 require.NoError(t, err) 465 case DeleteAction: 466 err = rightMut.Delete(context.Background(), key(testCase.key)) 467 require.NoError(t, err) 468 } 469 } 470 471 ctx := sql.NewEmptyContext() 472 473 updatedRows, err := leftMut.Map(ctx) 474 require.NoError(t, err) 475 mergeRows, err := rightMut.Map(ctx) 476 require.NoError(t, err) 477 478 rootTbl, err := doltdb.NewTable(ctx, vrw, ns, sch, durable.IndexFromProllyMap(updatedRows), nil, nil) 479 require.NoError(t, err) 480 rootTbl, err = rebuildAllProllyIndexes(ctx, rootTbl) 481 require.NoError(t, err) 482 483 mergeTbl, err := doltdb.NewTable(ctx, vrw, ns, sch, durable.IndexFromProllyMap(mergeRows), nil, nil) 484 require.NoError(t, err) 485 mergeTbl, err = rebuildAllProllyIndexes(ctx, mergeTbl) 486 require.NoError(t, err) 487 488 ancTbl, err := doltdb.NewTable(ctx, vrw, ns, sch, durable.IndexFromProllyMap(initialRows), nil, nil) 489 require.NoError(t, err) 490 ancTbl, err = rebuildAllProllyIndexes(ctx, ancTbl) 491 require.NoError(t, err) 492 493 rightCm, baseCm, root, mergeRoot, ancRoot := buildLeftRightAncCommitsAndBranches(t, ddb, rootTbl, mergeTbl, ancTbl) 494 495 artifactMap, err := prolly.NewArtifactMapFromTuples(ctx, ns, kD) 496 require.NoError(t, err) 497 artEditor := artifactMap.Editor() 498 499 baseCmHash, err := baseCm.HashOf() 500 require.NoError(t, err) 501 rightCmHash, err := rightCm.HashOf() 502 require.NoError(t, err) 503 504 m := prolly.ConflictMetadata{ 505 BaseRootIsh: baseCmHash, 506 } 507 d, err := json.Marshal(m) 508 require.NoError(t, err) 509 510 for _, testCase := range testRows { 511 if testCase.conflict { 512 err = artEditor.Add(ctx, key(testCase.key), rightCmHash, prolly.ArtifactTypeConflict, d) 513 require.NoError(t, err) 514 } 515 } 516 517 expectedArtifacts, err := artEditor.Flush(ctx) 518 require.NoError(t, err) 519 520 return ddb, vrw, ns, rightCm, baseCm, root, mergeRoot, ancRoot, durable.IndexFromProllyMap(expectedRows), expectedArtifacts 521 } 522 523 func setupNomsMergeTest(t *testing.T) (types.ValueReadWriter, tree.NodeStore, doltdb.Rootish, doltdb.Rootish, doltdb.RootValue, doltdb.RootValue, doltdb.RootValue, types.Map, types.Map, *MergeStats) { 524 ddb := mustMakeEmptyRepo(t) 525 vrw := ddb.ValueReadWriter() 526 ns := ddb.NodeStore() 527 sortTests(testRows) 528 529 var initalKVs []types.Value 530 var expectedKVs []types.Value 531 var expectedConflictsKVs []types.Value 532 for _, testCase := range testRows { 533 if testCase.initialValue != nil { 534 initalKVs = append(initalKVs, nomsKey(testCase.key), testCase.initialValue.nomsValue()) 535 } 536 if testCase.expectedValue != nil { 537 expectedKVs = append(expectedKVs, nomsKey(testCase.key), testCase.expectedValue.nomsValue()) 538 } 539 if testCase.conflict { 540 expectedConflictsKVs = append( 541 expectedConflictsKVs, 542 nomsKey(testCase.key), 543 mustTuple(conflict.NewConflict( 544 unwrapNoms(testCase.initialValue), 545 unwrapNoms(testCase.leftValue), 546 unwrapNoms(testCase.rightValue), 547 ).ToNomsList(vrw)), 548 ) 549 } 550 } 551 initialRows, err := types.NewMap(context.Background(), vrw, initalKVs...) 552 require.NoError(t, err) 553 expectedRows, err := types.NewMap(context.Background(), vrw, expectedKVs...) 554 require.NoError(t, err) 555 expectedConflicts, err := types.NewMap(context.Background(), vrw, expectedConflictsKVs...) 556 require.NoError(t, err) 557 558 leftE := initialRows.Edit() 559 rightE := initialRows.Edit() 560 for _, testCase := range testRows { 561 switch testCase.leftAction { 562 case NoopAction: 563 break 564 case InsertAction, UpdateAction: 565 leftE.Set(nomsKey(testCase.key), testCase.leftValue.nomsValue()) 566 case DeleteAction: 567 leftE.Remove(nomsKey(testCase.key)) 568 } 569 570 switch testCase.rightAction { 571 case NoopAction: 572 break 573 case InsertAction, UpdateAction: 574 rightE.Set(nomsKey(testCase.key), testCase.rightValue.nomsValue()) 575 case DeleteAction: 576 rightE.Remove(nomsKey(testCase.key)) 577 } 578 } 579 580 updatedRows, err := leftE.Map(context.Background()) 581 require.NoError(t, err) 582 mergeRows, err := rightE.Map(context.Background()) 583 require.NoError(t, err) 584 585 tbl, err := doltdb.NewNomsTable(context.Background(), vrw, ns, sch, initialRows, nil, nil) 586 require.NoError(t, err) 587 tbl, err = editor.RebuildAllIndexes(context.Background(), tbl, editor.TestEditorOptions(vrw)) 588 require.NoError(t, err) 589 590 updatedTbl, err := doltdb.NewNomsTable(context.Background(), vrw, ns, sch, updatedRows, nil, nil) 591 require.NoError(t, err) 592 updatedTbl, err = editor.RebuildAllIndexes(context.Background(), updatedTbl, editor.TestEditorOptions(vrw)) 593 require.NoError(t, err) 594 595 mergeTbl, err := doltdb.NewNomsTable(context.Background(), vrw, ns, sch, mergeRows, nil, nil) 596 require.NoError(t, err) 597 mergeTbl, err = editor.RebuildAllIndexes(context.Background(), mergeTbl, editor.TestEditorOptions(vrw)) 598 require.NoError(t, err) 599 600 ancTable, err := doltdb.NewNomsTable(context.Background(), vrw, ns, sch, initialRows, nil, nil) 601 require.NoError(t, err) 602 ancTable, err = editor.RebuildAllIndexes(context.Background(), ancTable, editor.TestEditorOptions(vrw)) 603 require.NoError(t, err) 604 605 rightCm, ancCommit, root, mergeRoot, ancRoot := buildLeftRightAncCommitsAndBranches(t, ddb, updatedTbl, mergeTbl, ancTable) 606 607 return vrw, ns, rightCm, ancCommit, root, mergeRoot, ancRoot, expectedRows, expectedConflicts, calcExpectedStats(t) 608 } 609 610 // rebuildAllProllyIndexes builds the data for the secondary indexes in |tbl|'s 611 // schema. 612 func rebuildAllProllyIndexes(ctx *sql.Context, tbl *doltdb.Table) (*doltdb.Table, error) { 613 sch, err := tbl.GetSchema(ctx) 614 if err != nil { 615 return nil, err 616 } 617 618 if sch.Indexes().Count() == 0 { 619 return tbl, nil 620 } 621 622 indexes, err := tbl.GetIndexSet(ctx) 623 if err != nil { 624 return nil, err 625 } 626 627 tableRowData, err := tbl.GetRowData(ctx) 628 if err != nil { 629 return nil, err 630 } 631 primary := durable.ProllyMapFromIndex(tableRowData) 632 633 for _, index := range sch.Indexes().AllIndexes() { 634 rebuiltIndexRowData, err := creation.BuildSecondaryProllyIndex(ctx, tbl.ValueReadWriter(), tbl.NodeStore(), sch, tableName, index, primary) 635 if err != nil { 636 return nil, err 637 } 638 639 indexes, err = indexes.PutIndex(ctx, index.Name(), rebuiltIndexRowData) 640 if err != nil { 641 return nil, err 642 } 643 } 644 645 return tbl.SetIndexSet(ctx, indexes) 646 } 647 648 func calcExpectedStats(t *testing.T) *MergeStats { 649 s := &MergeStats{Operation: TableModified} 650 for _, testCase := range testRows { 651 if (testCase.leftAction == InsertAction) != (testCase.rightAction == InsertAction) { 652 if testCase.leftAction == UpdateAction || testCase.rightAction == UpdateAction || 653 testCase.leftAction == DeleteAction || testCase.rightAction == DeleteAction { 654 // Either the row exists in the ancestor commit and we are 655 // deleting or updating it, or the row doesn't exist and we are 656 // inserting it. 657 t.Fatalf("it's impossible for an insert to be paired with an update or delete") 658 } 659 } 660 661 if testCase.leftAction == NoopAction { 662 switch testCase.rightAction { 663 case NoopAction: 664 case DeleteAction: 665 s.Deletes++ 666 case InsertAction: 667 s.Adds++ 668 case UpdateAction: 669 s.Modifications++ 670 } 671 continue 672 } 673 674 if testCase.rightAction == NoopAction { 675 switch testCase.leftAction { 676 case NoopAction: 677 case DeleteAction: 678 s.Deletes++ 679 case InsertAction: 680 s.Adds++ 681 case UpdateAction: 682 s.Modifications++ 683 } 684 continue 685 } 686 687 if testCase.conflict { 688 // (UpdateAction, DeleteAction), 689 // (DeleteAction, UpdateAction), 690 // (UpdateAction, UpdateAction) with conflict, 691 // (InsertAction, InsertAction) with conflict 692 s.DataConflicts++ 693 continue 694 } 695 696 if testCase.leftAction == InsertAction && testCase.rightAction == InsertAction { 697 // Equivalent inserts 698 continue 699 } 700 701 if !valutil.NilSafeEqCheck(unwrapNoms(testCase.leftValue), unwrapNoms(testCase.rightValue)) { 702 s.Modifications++ 703 continue 704 } 705 } 706 707 return s 708 } 709 710 func mustMakeEmptyRepo(t *testing.T) *doltdb.DoltDB { 711 ddb, _ := doltdb.LoadDoltDB(context.Background(), types.Format_Default, doltdb.InMemDoltDB, filesys2.LocalFS) 712 err := ddb.WriteEmptyRepo(context.Background(), env.DefaultInitBranch, name, email) 713 require.NoError(t, err) 714 return ddb 715 } 716 717 func buildLeftRightAncCommitsAndBranches(t *testing.T, ddb *doltdb.DoltDB, rootTbl, mergeTbl, ancTbl *doltdb.Table) (doltdb.Rootish, doltdb.Rootish, doltdb.RootValue, doltdb.RootValue, doltdb.RootValue) { 718 mainHeadSpec, _ := doltdb.NewCommitSpec(env.DefaultInitBranch) 719 optCmt, err := ddb.Resolve(context.Background(), mainHeadSpec, nil) 720 require.NoError(t, err) 721 mainHead, ok := optCmt.ToCommit() 722 require.True(t, ok) 723 724 mRoot, err := mainHead.GetRootValue(context.Background()) 725 require.NoError(t, err) 726 727 mRoot, err = mRoot.PutTable(context.Background(), doltdb.TableName{Name: tableName}, ancTbl) 728 require.NoError(t, err) 729 730 updatedRoot, err := mRoot.PutTable(context.Background(), doltdb.TableName{Name: tableName}, rootTbl) 731 require.NoError(t, err) 732 733 mergeRoot, err := mRoot.PutTable(context.Background(), doltdb.TableName{Name: tableName}, mergeTbl) 734 require.NoError(t, err) 735 736 r, mainHash, err := ddb.WriteRootValue(context.Background(), mRoot) 737 require.NoError(t, err) 738 mRoot = r 739 r, hash, err := ddb.WriteRootValue(context.Background(), updatedRoot) 740 require.NoError(t, err) 741 updatedRoot = r 742 r, mergeHash, err := ddb.WriteRootValue(context.Background(), mergeRoot) 743 require.NoError(t, err) 744 mergeRoot = r 745 746 meta, err := datas.NewCommitMeta(name, email, "fake") 747 require.NoError(t, err) 748 initialCommit, err := ddb.Commit(context.Background(), mainHash, ref.NewBranchRef(env.DefaultInitBranch), meta) 749 require.NoError(t, err) 750 commit, err := ddb.Commit(context.Background(), hash, ref.NewBranchRef(env.DefaultInitBranch), meta) 751 require.NoError(t, err) 752 753 err = ddb.NewBranchAtCommit(context.Background(), ref.NewBranchRef("to-merge"), initialCommit, nil) 754 require.NoError(t, err) 755 mergeCommit, err := ddb.Commit(context.Background(), mergeHash, ref.NewBranchRef("to-merge"), meta) 756 require.NoError(t, err) 757 758 root, err := commit.GetRootValue(context.Background()) 759 require.NoError(t, err) 760 761 optCmt, err = doltdb.GetCommitAncestor(context.Background(), commit, mergeCommit) 762 require.NoError(t, err) 763 ancCm, ok := optCmt.ToCommit() 764 require.True(t, ok) 765 766 ancRoot, err := ancCm.GetRootValue(context.Background()) 767 require.NoError(t, err) 768 769 ff, err := commit.CanFastForwardTo(context.Background(), mergeCommit) 770 require.NoError(t, err) 771 require.False(t, ff) 772 773 return mergeCommit, ancCm, root, mergeRoot, ancRoot 774 } 775 776 var kD = sch.GetKeyDescriptor() 777 var kB = val.NewTupleBuilder(kD) 778 779 func key(i int) val.Tuple { 780 kB.PutInt64(0, int64(i)) 781 return kB.Build(syncPool) 782 } 783 784 func nomsKey(i int) types.Value { 785 return mustTuple(types.NewTuple(types.Format_Default, types.Uint(idTag), types.Int(i))) 786 } 787 788 func unwrap(v *rowV) val.Tuple { 789 if v == nil { 790 return nil 791 } 792 return v.value() 793 } 794 795 func unwrapNoms(v *rowV) types.Value { 796 if v == nil { 797 return nil 798 } 799 return v.nomsValue() 800 } 801 802 func mustTuple(tpl types.Tuple, err error) types.Tuple { 803 if err != nil { 804 panic(err) 805 } 806 807 return tpl 808 } 809 810 func mustString(str string, err error) string { 811 if err != nil { 812 panic(err) 813 } 814 815 return str 816 } 817 818 func MustDebugFormatProlly(t *testing.T, m prolly.Map) string { 819 s, err := prolly.DebugFormat(context.Background(), m) 820 require.NoError(t, err) 821 return s 822 } 823 824 func MustEqualProlly(t *testing.T, name string, expected, actual prolly.Map) { 825 require.Equal(t, expected.HashOf(), actual.HashOf(), 826 "hashes differed for %s. expected: %s\nactual: %s", name, MustDebugFormatProlly(t, expected), MustDebugFormatProlly(t, actual)) 827 } 828 829 func MustEqualArtifactMap(t *testing.T, expected prolly.ArtifactMap, actual prolly.ArtifactMap) { 830 require.Equal(t, expected.HashOf(), actual.HashOf(), 831 "artifact map hashes differed.") 832 }