Skip to content

Commit 2304fca

Browse files
committed
refactor build infio
1 parent b12a8d2 commit 2304fca

File tree

8 files changed

+191
-59
lines changed

8 files changed

+191
-59
lines changed

.github/workflows/all.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,3 @@ jobs:
7070
MVTEST_SRC: ${{matrix.topology.srcConnStr}}
7171
MVTEST_DST: ${{matrix.topology.dstConnStr}}
7272
MVTEST_META: mongodb://localhost:27040
73-
MVTEST_TOPOLOGY: ${{matrix.topology.name}}

internal/partitions/partition.go

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ func (p *Partition) FindCmd(
137137
// (e.g. use the partitions on the source to read the destination for verification)
138138
// If the passed-in buildinfo indicates a mongodb version < 5.0, type bracketing is not used.
139139
// filterAndPredicates is a slice of filter criteria that's used to construct the "filter" field in the find option.
140-
func (p *Partition) GetFindOptions(buildInfo *bson.M, filterAndPredicates bson.A) bson.D {
140+
func (p *Partition) GetFindOptions(buildInfo *util.BuildInfo, filterAndPredicates bson.A) bson.D {
141141
if p == nil {
142142
if len(filterAndPredicates) > 0 {
143143
return bson.D{{"filter", bson.D{{"$and", filterAndPredicates}}}}
@@ -160,16 +160,9 @@ func (p *Partition) GetFindOptions(buildInfo *bson.M, filterAndPredicates bson.A
160160
allowTypeBracketing := false
161161
if buildInfo != nil {
162162
allowTypeBracketing = true
163-
versionArray, ok := (*buildInfo)["versionArray"].(bson.A)
164-
//bson values are int32 or int64, never int.
165-
if ok {
166-
majorVersion, ok := versionArray[0].(int32)
167-
if ok {
168-
allowTypeBracketing = majorVersion < 5
169-
} else {
170-
majorVersion64, _ := versionArray[0].(int64)
171-
allowTypeBracketing = majorVersion64 < 5
172-
}
163+
164+
if buildInfo.VersionArray != nil {
165+
allowTypeBracketing = buildInfo.VersionArray[0] < 5
173166
}
174167
}
175168
if !allowTypeBracketing {

internal/partitions/partition_test.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,43 +77,38 @@ func (suite *UnitTestSuite) TestVersioning() {
7777
filter := getFilterFromFindOptions(findOptions)
7878
suite.Require().Equal(expectedFilter, filter)
7979

80-
// 6.0 (int64)
81-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int64(6), int64(0), int64(0), int64(0)}}, nil)
82-
filter = getFilterFromFindOptions(findOptions)
83-
suite.Require().Equal(expectedFilter, filter)
84-
8580
// 6.0
86-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int32(6), int32(0), int32(0), int32(0)}}, nil)
81+
findOptions = partition.GetFindOptions(&util.BuildInfo{VersionArray: []int{6, 0, 0}}, nil)
8782
filter = getFilterFromFindOptions(findOptions)
8883
suite.Require().Equal(expectedFilter, filter)
8984

9085
// 5.3.0.9
91-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int32(5), int32(3), int32(0), int32(9)}}, nil)
86+
findOptions = partition.GetFindOptions(&util.BuildInfo{VersionArray: []int{5, 3, 0, 9}}, nil)
9287
filter = getFilterFromFindOptions(findOptions)
9388
suite.Require().Equal(expectedFilter, filter)
9489

9590
// 7.1.3.5
96-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int32(7), int32(1), int32(3), int32(5)}}, nil)
91+
findOptions = partition.GetFindOptions(&util.BuildInfo{VersionArray: []int{7, 1, 3, 5}}, nil)
9792
filter = getFilterFromFindOptions(findOptions)
9893
suite.Require().Equal(expectedFilter, filter)
9994

10095
// 4.4 (int64)
101-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int64(4), int64(4), int64(0), int64(0)}}, nil)
96+
findOptions = partition.GetFindOptions(&util.BuildInfo{VersionArray: []int{4, 4, 0, 0}}, nil)
10297
filter = getFilterFromFindOptions(findOptions)
10398
suite.Require().Equal(expectedFilterWithTypeBracketing, filter)
10499

105100
// 4.4
106-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int32(4), int32(4), int32(0), int32(0)}}, nil)
101+
findOptions = partition.GetFindOptions(&util.BuildInfo{VersionArray: []int{4, 4, 0, 0}}, nil)
107102
filter = getFilterFromFindOptions(findOptions)
108103
suite.Require().Equal(expectedFilterWithTypeBracketing, filter)
109104

110105
// 4.2
111-
findOptions = partition.GetFindOptions(&bson.M{"versionArray": bson.A{int32(4), int32(2), int32(0), int32(0)}}, nil)
106+
findOptions = partition.GetFindOptions(&util.BuildInfo{VersionArray: []int{4, 2, 0, 0}}, nil)
112107
filter = getFilterFromFindOptions(findOptions)
113108
suite.Require().Equal(expectedFilterWithTypeBracketing, filter)
114109

115110
// No version array -- assume old, require type bracketing.
116-
findOptions = partition.GetFindOptions(&bson.M{"notVersionArray": bson.A{6, int32(0), int32(0), int32(0)}}, nil)
111+
findOptions = partition.GetFindOptions(&util.BuildInfo{}, nil)
117112
filter = getFilterFromFindOptions(findOptions)
118113
suite.Require().Equal(expectedFilterWithTypeBracketing, filter)
119114
}

internal/util/buildinfo.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package util
2+
3+
import (
4+
"context"
5+
6+
"github.com/10gen/migration-verifier/mbson"
7+
"github.com/pkg/errors"
8+
"go.mongodb.org/mongo-driver/bson"
9+
"go.mongodb.org/mongo-driver/mongo"
10+
)
11+
12+
type BuildInfo struct {
13+
VersionArray []int
14+
IsSharded bool
15+
}
16+
17+
func GetBuildInfo(ctx context.Context, client *mongo.Client) (BuildInfo, error) {
18+
commandResult := client.Database("admin").RunCommand(ctx, bson.D{{"buildinfo", 1}})
19+
20+
rawResp, err := commandResult.Raw()
21+
if err != nil {
22+
return BuildInfo{}, errors.Wrap(err, "failed to fetch build info")
23+
}
24+
25+
bi := BuildInfo{}
26+
_, err = mbson.RawLookup(rawResp, &bi.VersionArray, "versionArray")
27+
if err != nil {
28+
return BuildInfo{}, errors.Wrap(err, "failed to decode build info version array")
29+
}
30+
31+
var msg string
32+
_, err = mbson.RawLookup(rawResp, &msg, "msg")
33+
bi.IsSharded = msg == "isdbgrid"
34+
35+
return bi, nil
36+
}

internal/verifier/integration_test_suite.go

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package verifier
22

33
import (
44
"context"
5-
"os"
65
"strings"
76

7+
"github.com/10gen/migration-verifier/internal/util"
88
mapset "github.com/deckarep/golang-set/v2"
99
"github.com/pkg/errors"
10+
"github.com/samber/lo"
1011
"github.com/stretchr/testify/suite"
1112
"go.mongodb.org/mongo-driver/bson"
1213
"go.mongodb.org/mongo-driver/mongo"
@@ -121,19 +122,10 @@ func (suite *IntegrationTestSuite) TearDownTest() {
121122
}
122123

123124
func (suite *IntegrationTestSuite) GetTopology() TestTopology {
124-
rawTopology, found := os.LookupEnv(topologyEnvVar)
125+
buildInfo, err := util.GetBuildInfo(suite.Context(), suite.srcMongoClient)
126+
suite.Require().NoError(err, "should read source's build info")
125127

126-
suite.Require().True(found, "Environment must contain %#q.", topologyEnvVar)
127-
128-
topology := TestTopology(rawTopology)
129-
130-
suite.Require().Contains(
131-
knownTopologies,
132-
topology,
133-
"%#q must be a known value.",
134-
)
135-
136-
return topology
128+
return lo.Ternary(buildInfo.IsSharded, TopologySharded, "")
137129
}
138130

139131
func (suite *IntegrationTestSuite) BuildVerifier() *Verifier {

internal/verifier/migration_verifier.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/10gen/migration-verifier/internal/reportutils"
2222
"github.com/10gen/migration-verifier/internal/retry"
2323
"github.com/10gen/migration-verifier/internal/types"
24+
"github.com/10gen/migration-verifier/internal/util"
2425
"github.com/10gen/migration-verifier/internal/uuidutil"
2526
"github.com/olekukonko/tablewriter"
2627
"github.com/pkg/errors"
@@ -88,8 +89,8 @@ type Verifier struct {
8889
metaClient *mongo.Client
8990
srcClient *mongo.Client
9091
dstClient *mongo.Client
91-
srcBuildInfo *bson.M
92-
dstBuildInfo *bson.M
92+
srcBuildInfo *util.BuildInfo
93+
dstBuildInfo *util.BuildInfo
9394
numWorkers int
9495
failureDisplaySize int64
9596

@@ -276,21 +277,33 @@ func (verifier *Verifier) SetSrcURI(ctx context.Context, uri string) error {
276277
var err error
277278
verifier.srcClient, err = mongo.Connect(ctx, opts)
278279
if err != nil {
279-
return errors.Wrapf(err, "failed to connect to %#q", uri)
280+
return errors.Wrapf(err, "failed to connect to source %#q", uri)
280281
}
281-
verifier.srcBuildInfo, err = getBuildInfo(ctx, verifier.srcClient)
282-
return err
282+
283+
buildInfo, err := util.GetBuildInfo(ctx, verifier.srcClient)
284+
if err != nil {
285+
return errors.Wrap(err, "failed to read source build info")
286+
}
287+
288+
verifier.srcBuildInfo = &buildInfo
289+
return nil
283290
}
284291

285292
func (verifier *Verifier) SetDstURI(ctx context.Context, uri string) error {
286293
opts := verifier.getClientOpts(uri)
287294
var err error
288295
verifier.dstClient, err = mongo.Connect(ctx, opts)
289296
if err != nil {
290-
return err
297+
return errors.Wrapf(err, "failed to connect to destination %#q", uri)
291298
}
292-
verifier.dstBuildInfo, err = getBuildInfo(ctx, verifier.dstClient)
293-
return err
299+
300+
buildInfo, err := util.GetBuildInfo(ctx, verifier.dstClient)
301+
if err != nil {
302+
return errors.Wrap(err, "failed to read destination build info")
303+
}
304+
305+
verifier.dstBuildInfo = &buildInfo
306+
return nil
294307
}
295308

296309
func (verifier *Verifier) SetServerPort(port int) {
@@ -429,7 +442,7 @@ func (verifier *Verifier) maybeAppendGlobalFilterToPredicates(predicates bson.A)
429442
return append(predicates, verifier.globalFilter)
430443
}
431444

432-
func (verifier *Verifier) getDocumentsCursor(ctx context.Context, collection *mongo.Collection, buildInfo *bson.M,
445+
func (verifier *Verifier) getDocumentsCursor(ctx context.Context, collection *mongo.Collection, buildInfo *util.BuildInfo,
433446
startAtTs *primitive.Timestamp, task *VerificationTask) (*mongo.Cursor, error) {
434447
var findOptions bson.D
435448
runCommandOptions := options.RunCmd()
@@ -1402,16 +1415,3 @@ func (verifier *Verifier) getNamespaces(ctx context.Context, fieldName string) (
14021415
}
14031416
return namespaces, nil
14041417
}
1405-
1406-
func getBuildInfo(ctx context.Context, client *mongo.Client) (*bson.M, error) {
1407-
commandResult := client.Database("admin").RunCommand(ctx, bson.D{{"buildinfo", 1}})
1408-
if commandResult.Err() != nil {
1409-
return nil, commandResult.Err()
1410-
}
1411-
var buildInfoMap bson.M
1412-
err := commandResult.Decode(&buildInfoMap)
1413-
if err != nil {
1414-
return nil, err
1415-
}
1416-
return &buildInfoMap, nil
1417-
}

mbson/bson_raw.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package mbson
2+
3+
import (
4+
"github.com/pkg/errors"
5+
"go.mongodb.org/mongo-driver/bson"
6+
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
7+
)
8+
9+
// RawLookup combines bson.Raw’s LookupErr method with an additional
10+
// unmarshal step. The result is a convenient way to extract values from
11+
// bson.Raw. The returned boolean indicates whether the value was found.
12+
func RawLookup[T any](doc bson.Raw, dest *T, keys ...string) (bool, error) {
13+
val, err := doc.LookupErr(keys...)
14+
15+
if err == nil {
16+
return true, val.Unmarshal(dest)
17+
} else if errors.Is(err, bsoncore.ErrElementNotFound) {
18+
return false, nil
19+
}
20+
21+
return false, errors.Wrapf(err, "failed to look up %+v in BSON doc", keys)
22+
}
23+
24+
// RawContains is like RawLookup but makes no effort to unmarshal
25+
// the value.
26+
func RawContains(doc bson.Raw, keys ...string) (bool, error) {
27+
val := any(nil)
28+
return RawLookup(doc, &val, keys...)
29+
}

mbson/unit_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package mbson
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/suite"
7+
"go.mongodb.org/mongo-driver/bson"
8+
"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
9+
)
10+
11+
type UnitTestSuite struct {
12+
suite.Suite
13+
}
14+
15+
func TestUnitTestSuite(t *testing.T) {
16+
ts := new(UnitTestSuite)
17+
suite.Run(t, ts)
18+
}
19+
20+
func (s *UnitTestSuite) Test_RawLookup() {
21+
myDoc := bson.D{
22+
{"foo", 1},
23+
{"bar", "baz"},
24+
{"quux", bson.A{
25+
123,
26+
bson.D{{"hey", "ho"}},
27+
}},
28+
}
29+
30+
myRaw, err := bson.Marshal(myDoc)
31+
s.Require().NoError(err)
32+
33+
var myInt int
34+
var myStr string
35+
36+
found, err := RawLookup(myRaw, &myInt, "foo")
37+
s.Require().True(found)
38+
s.Require().NoError(err)
39+
s.Assert().EqualValues(1, myInt)
40+
41+
found, err = RawLookup(myRaw, &myInt, "quux", "0")
42+
s.Require().True(found)
43+
s.Require().NoError(err)
44+
s.Assert().EqualValues(123, myInt)
45+
46+
found, err = RawLookup(myRaw, &myStr, "quux", "1", "hey")
47+
s.Require().True(found)
48+
s.Require().NoError(err)
49+
s.Assert().EqualValues("ho", myStr)
50+
51+
found, err = RawLookup(myRaw, &myStr, "not there")
52+
s.Require().NoError(err)
53+
s.Assert().False(found)
54+
55+
myRaw = myRaw[:len(myRaw)-2]
56+
_, err = RawLookup(myRaw, &myStr, "not there")
57+
s.Assert().ErrorAs(err, &bsoncore.InsufficientBytesError{})
58+
}
59+
60+
func (s *UnitTestSuite) Test_RawContains() {
61+
myDoc := bson.D{
62+
{"foo", 1},
63+
{"bar", "baz"},
64+
{"quux", bson.A{
65+
123,
66+
bson.D{{"hey", "ho"}},
67+
}},
68+
}
69+
70+
myRaw, err := bson.Marshal(myDoc)
71+
s.Require().NoError(err)
72+
73+
has, err := RawContains(myRaw, "foo")
74+
s.Require().NoError(err)
75+
s.Assert().True(has, "`foo` should exist")
76+
77+
has, err = RawContains(myRaw, "quux", "1", "hey")
78+
s.Require().NoError(err)
79+
s.Assert().True(has, "deep lookup should work")
80+
81+
has, err = RawContains(myRaw, "not there")
82+
s.Require().NoError(err)
83+
s.Assert().False(has, "missing element should not exist")
84+
85+
myRaw = myRaw[:len(myRaw)-2]
86+
_, err = RawContains(myRaw, "not there")
87+
s.Assert().ErrorAs(err, &bsoncore.InsufficientBytesError{})
88+
}

0 commit comments

Comments
 (0)