Skip to content

Commit e3b46be

Browse files
committed
REP-6088 Fix bugs from PR #117
- Mismatches were previously shown in an indeterminate order. Now they’re consistently sorted by the mismatched documents’ `_id`. - Documents with missing fields were being logged as entirely missing. That logic is corrected here. - The logic to create the table of missing/changed documents previously iterated through the _ids persisted in the task rather than the actual missing/changed documents. This was appropriate when that list stored mismatches but is no longer correct since the list now always stores the list of documents to check in the task. Thus, if there were only a handful of missing documents in a recheck task that contained thousands of document IDs, all of that task’s document IDs would be logged as missing. This was an oversight from PR #117, which should have updated the logic to build that table as it migrated that for the mismatched-documents table. This changeset does the necessary update.
1 parent eeb9924 commit e3b46be

File tree

4 files changed

+106
-6
lines changed

4 files changed

+106
-6
lines changed

internal/verifier/migration_verifier_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"regexp"
1616
"slices"
1717
"sort"
18+
"strings"
1819
"testing"
1920
"time"
2021

@@ -27,6 +28,7 @@ import (
2728
"github.com/10gen/migration-verifier/mslices"
2829
"github.com/cespare/permute/v2"
2930
"github.com/rs/zerolog"
31+
"github.com/samber/lo"
3032
"github.com/stretchr/testify/assert"
3133
"github.com/stretchr/testify/require"
3234
"github.com/stretchr/testify/suite"
@@ -1240,6 +1242,88 @@ func (suite *IntegrationTestSuite) TestVerifierCompareIndexes() {
12401242
}
12411243
}
12421244

1245+
func (suite *IntegrationTestSuite) TestVerifierDocMismatches() {
1246+
ctx := suite.Context()
1247+
1248+
suite.Require().NoError(
1249+
suite.srcMongoClient.
1250+
Database("test").
1251+
Collection("coll").Drop(ctx),
1252+
)
1253+
suite.Require().NoError(
1254+
suite.dstMongoClient.
1255+
Database("test").
1256+
Collection("coll").Drop(ctx),
1257+
)
1258+
1259+
_, err := suite.srcMongoClient.
1260+
Database("test").
1261+
Collection("coll").
1262+
InsertMany(
1263+
ctx,
1264+
lo.RepeatBy(
1265+
20,
1266+
func(index int) any {
1267+
return bson.D{
1268+
{"_id", 100000 + index},
1269+
{"foo", 3},
1270+
}
1271+
},
1272+
),
1273+
)
1274+
suite.Require().NoError(err)
1275+
1276+
// The first has a mismatched `foo` value,
1277+
// and the 2nd lacks `foo` entirely.
1278+
_, err = suite.dstMongoClient.
1279+
Database("test").
1280+
Collection("coll").
1281+
InsertMany(ctx, lo.ToAnySlice([]bson.D{
1282+
{{"_id", 100000}, {"foo", 1}},
1283+
{{"_id", 100001}},
1284+
}))
1285+
suite.Require().NoError(err)
1286+
1287+
verifier := suite.BuildVerifier()
1288+
verifier.failureDisplaySize = 10
1289+
1290+
ns := "test.coll"
1291+
verifier.SetSrcNamespaces([]string{ns})
1292+
verifier.SetDstNamespaces([]string{ns})
1293+
verifier.SetNamespaceMap()
1294+
1295+
runner := RunVerifierCheck(ctx, suite.T(), verifier)
1296+
suite.Require().NoError(runner.AwaitGenerationEnd())
1297+
1298+
builder := &strings.Builder{}
1299+
_, _, err = verifier.reportDocumentMismatches(ctx, builder)
1300+
suite.Require().NoError(err)
1301+
1302+
suite.Assert().Contains(
1303+
builder.String(),
1304+
"100009",
1305+
"summary should show an early mismatch",
1306+
)
1307+
1308+
suite.Assert().Contains(
1309+
builder.String(),
1310+
" 10 ",
1311+
"summary should show the # of missing docs shown",
1312+
)
1313+
1314+
suite.Assert().Contains(
1315+
builder.String(),
1316+
" 18 ",
1317+
"summary should show the total # of missing/changed documents",
1318+
)
1319+
1320+
suite.Assert().NotContains(
1321+
builder.String(),
1322+
"100019",
1323+
"summary should NOT show a late mismatch",
1324+
)
1325+
}
1326+
12431327
func (suite *IntegrationTestSuite) TestVerifierCompareIndexSpecs() {
12441328
ctx := suite.Context()
12451329
verifier := suite.BuildVerifier()

internal/verifier/mismatches.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"go.mongodb.org/mongo-driver/bson"
1010
"go.mongodb.org/mongo-driver/bson/primitive"
1111
"go.mongodb.org/mongo-driver/mongo"
12+
"go.mongodb.org/mongo-driver/mongo/options"
1213
)
1314

1415
const (
@@ -49,6 +50,11 @@ func getMismatchesForTasks(
4950
bson.D{
5051
{"task", bson.D{{"$in", taskIDs}}},
5152
},
53+
options.Find().SetSort(
54+
bson.D{
55+
{"detail.id", 1},
56+
},
57+
),
5258
)
5359

5460
if err != nil {

internal/verifier/result.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ type VerificationResult struct {
3636
DstTimestamp option.Option[primitive.Timestamp]
3737
}
3838

39-
func (vr VerificationResult) IsMissing() bool {
40-
return vr.Details == Missing
39+
// DocumentIsMissing returns a boolean that indicates whether the
40+
// VerificationResult indicates a document that is missing on either
41+
// source or destination.
42+
func (vr VerificationResult) DocumentIsMissing() bool {
43+
// NB: Missing gets set as the Details value when a field is missing
44+
// but the document exists. To ascertain that the document is entirely
45+
// absent we have to check Field as well.
46+
return vr.Details == Missing && vr.Field == ""
4147
}

internal/verifier/summary.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func (verifier *Verifier) reportDocumentMismatches(ctx context.Context, strBuild
144144
missingCount := lo.CountBy(
145145
discrepancies,
146146
func(d VerificationResult) bool {
147-
return d.IsMissing()
147+
return d.DocumentIsMissing()
148148
},
149149
)
150150

@@ -171,7 +171,7 @@ func (verifier *Verifier) reportDocumentMismatches(ctx context.Context, strBuild
171171
OUTA:
172172
for _, task := range failedTasks {
173173
for _, d := range taskDiscrepancies[task.PrimaryKey] {
174-
if d.IsMissing() {
174+
if d.DocumentIsMissing() {
175175
continue
176176
}
177177

@@ -207,14 +207,18 @@ OUTA:
207207
printAll = int64(missingOrChangedCount) < (verifier.failureDisplaySize + int64(0.25*float32(verifier.failureDisplaySize)))
208208
OUTB:
209209
for _, task := range failedTasks {
210-
for _, _id := range task.Ids {
210+
for _, d := range taskDiscrepancies[task.PrimaryKey] {
211+
if !d.DocumentIsMissing() {
212+
continue
213+
}
214+
211215
if !printAll && missingOrChangedDocsTableRows >= verifier.failureDisplaySize {
212216
break OUTB
213217
}
214218

215219
missingOrChangedDocsTableRows++
216220
missingOrChangedDocsTable.Append([]string{
217-
fmt.Sprintf("%v", _id),
221+
fmt.Sprintf("%v", d.ID),
218222
fmt.Sprintf("%v", task.QueryFilter.Namespace),
219223
fmt.Sprintf("%v", task.QueryFilter.To),
220224
})

0 commit comments

Comments
 (0)