Skip to content

Commit 53ded13

Browse files
authored
REP-5306 Migrate integration tests to use externally-provisioned clusters. (#48)
This project’s test suite has been provisioning its own clusters via custom logic. That logic can’t provision sharded clusters, though. REP-5299 (PR #47) documents a fix for sharding. To test that ticket’s fix we need to run the test suite against sharded clusters. Thus, this changeset: - Removes the suite’s custom provisioning logic. - Uses [mtools](https://github.com/rueckstiess/mtools) and [m](https://www.npmjs.com/package/m) to provision clusters. - Adds tests against 7.0 and 8.0, while removing tests against rapid releases like 6.2. Additional notes/changes: - CI now runs the tests with race detection. - A handful of tests seem to break in sharded clusters. REP-5299 may resolve those, so I’m marking them as skipped for now. - macOS is removed from CI. There seems little reason to test it, and it’s reliably slower than Ubuntu. - CI now just uses Go’s `stable` version. There’s little reason to retain compatibility with prior Go releases. - The metadata cluster is always unsharded because there seems little reason to shard it. It’s also always MongoDB’s latest stable release because there seems little reason to test older releases. - The change stream thread now Close()s its change stream. - The logs about resume token timestamps now just say `timestampTime` rather than `clockTime`. - Since the tests now need buildInfo, this changeset refactors that to a struct and moves it to `util`.
1 parent a1945d7 commit 53ded13

File tree

9 files changed

+375
-644
lines changed

9 files changed

+375
-644
lines changed

.github/workflows/all.yml

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,43 @@ jobs:
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
os:
15-
- runsOn: macos-latest
16-
mongodb_distro: mongodb-macos-arm64
14+
mongodb_versions:
15+
- [ '4.2', '4.2' ]
16+
- [ '4.2', '4.4' ]
17+
- [ '4.2', '5.0' ]
18+
- [ '4.2', '6.0' ]
1719

18-
- runsOn: ubuntu-latest
19-
mongodb_distro: mongodb-linux-x86_64-ubuntu1804
20+
- [ '4.4', '4.4' ]
21+
- [ '4.4', '5.0' ]
22+
- [ '4.4', '6.0' ]
2023

21-
go_version:
24+
- [ '5.0', '5.0' ]
25+
- [ '5.0', '6.0' ]
26+
- [ '5.0', '7.0' ]
2227

23-
# This is hard-coded by design in order to catch inadvertent changes
24-
# to the minimum-required Go version to build migration-verifier.
25-
- '1.20'
26-
- stable
28+
- [ '6.0', '6.0' ]
29+
- [ '6.0', '7.0' ]
30+
- [ '6.0', '8.0' ]
2731

28-
runs-on: ${{matrix.os.runsOn}}
32+
- [ '7.0', '7.0' ]
33+
- [ '7.0', '8.0' ]
34+
35+
- [ '8.0', '8.0' ]
36+
37+
topology:
38+
- name: replset
39+
srcConnStr: mongodb://localhost:27020,localhost:27021,localhost:27022
40+
dstConnStr: mongodb://localhost:27030,localhost:27031,localhost:27032
41+
42+
- name: sharded
43+
args: --sharded 2
44+
srcConnStr: mongodb://localhost:27020
45+
dstConnStr: mongodb://localhost:27030
46+
47+
# There seems no good reason to test on other OSes … ?
48+
runs-on: ubuntu-latest
49+
50+
name: ${{ matrix.mongodb_versions[0] }} to ${{ matrix.mongodb_versions[1] }}, ${{ matrix.topology.name }}
2951

3052
steps:
3153
- name: Check out repository
@@ -34,12 +56,37 @@ jobs:
3456
- name: Fetch Go ${{ matrix.go_version }}
3557
uses: actions/setup-go@v5
3658
with:
37-
go-version: ${{ matrix.go_version }}
59+
go-version: stable
60+
61+
- name: Install m
62+
run: npm install -g m mongosh
63+
64+
- name: Install MongoDB ${{ matrix.mongodb_versions[0] }} (source)
65+
run: yes | m ${{ matrix.mongodb_versions[0] }} && dirname $(readlink $(which mongod)) > .srcpath
66+
67+
- name: Install MongoDB ${{ matrix.mongodb_versions[1] }} (destination)
68+
run: yes | m ${{ matrix.mongodb_versions[1] }} && dirname $(readlink $(which mongod)) > .dstpath
69+
70+
- name: Install latest stable MongoDB (metadata)
71+
run: yes | m stable && dirname $(readlink $(which mongod)) > .metapath
72+
73+
- name: Install mtools
74+
run: pipx install 'mtools[all]'
3875

3976
- name: Build
4077
run: go build main/migration_verifier.go
4178

79+
- name: Start clusters
80+
run: |-
81+
{
82+
echo "mlaunch init --binarypath $(cat .srcpath) --port 27020 --dir src --replicaset ${{ matrix.topology.args }}"
83+
echo "mlaunch init --binarypath $(cat .dstpath) --port 27030 --dir dst --replicaset ${{ matrix.topology.args }}"
84+
echo "mlaunch init --binarypath $(cat .metapath) --port 27040 --dir meta --replicaset --nodes 1"
85+
} | parallel
86+
4287
- name: Test
43-
run: go test -v ./...
88+
run: go test -v ./... -race
4489
env:
45-
MONGODB_DISTRO: ${{matrix.os.mongodb_distro}}
90+
MVTEST_SRC: ${{matrix.topology.srcConnStr}}
91+
MVTEST_DST: ${{matrix.topology.dstConnStr}}
92+
MVTEST_META: mongodb://localhost:27040

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,17 @@ On default settings it used about **200GB of RAM on m6id.metal machine when usin
147147
148148
**This means it does about 1TB/20min but it is HIGHLY dependent on the source and dest machines**
149149
150+
# Tests
151+
152+
This project’s tests run as normal Go tests, to, with `go test`.
153+
154+
`IntegrationTestSuite`'s tests require external clusters. You must provision these yourself.
155+
(See the project’s GitHub CI setup for one way to simplify it.) Once provisioned, set the relevant
156+
connection strings in the following environment variables:
157+
158+
- MVTEST_SRC
159+
- MVTEST_DST
160+
- MVTEST_META
150161
151162
# How the Verifier Works
152163

internal/verifier/change_stream.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ func (verifier *Verifier) GetChangeStreamFilter() []bson.D {
123123
}
124124

125125
func (verifier *Verifier) iterateChangeStream(ctx context.Context, cs *mongo.ChangeStream) {
126+
defer cs.Close(ctx)
127+
126128
var lastPersistedTime time.Time
127129

128130
persistResumeTokenIfNeeded := func() error {
@@ -179,6 +181,9 @@ func (verifier *Verifier) iterateChangeStream(ctx context.Context, cs *mongo.Cha
179181

180182
// If the context is canceled, return immmediately.
181183
case <-ctx.Done():
184+
verifier.logger.Debug().
185+
Err(ctx.Err()).
186+
Msg("Change stream quitting.")
182187
return
183188

184189
// If the changeStreamEnderChan has a message, the user has indicated that
@@ -319,7 +324,7 @@ func (verifier *Verifier) StartChangeStream(ctx context.Context) error {
319324
}
320325

321326
func addUnixTimeToLogEvent[T constraints.Integer](unixTime T, event *zerolog.Event) *zerolog.Event {
322-
return event.Time("clockTime", time.Unix(int64(unixTime), int64(0)))
327+
return event.Time("timestampTime", time.Unix(int64(unixTime), int64(0)))
323328
}
324329

325330
func (v *Verifier) getChangeStreamMetadataCollection() *mongo.Collection {

internal/verifier/change_stream_test.go

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ func TestChangeStreamFilter(t *testing.T) {
3333
// TestChangeStreamResumability creates a verifier, starts its change stream,
3434
// terminates that verifier, updates the source cluster, starts a new
3535
// verifier with change stream, and confirms that things look as they should.
36-
func (suite *MultiSourceVersionTestSuite) TestChangeStreamResumability() {
36+
func (suite *IntegrationTestSuite) TestChangeStreamResumability() {
3737
func() {
38-
verifier1 := buildVerifier(suite.T(), suite.srcMongoInstance, suite.dstMongoInstance, suite.metaMongoInstance)
38+
verifier1 := suite.BuildVerifier()
3939
ctx, cancel := context.WithCancel(context.Background())
4040
defer cancel()
4141
err := verifier1.StartChangeStream(ctx)
@@ -46,15 +46,15 @@ func (suite *MultiSourceVersionTestSuite) TestChangeStreamResumability() {
4646
defer cancel()
4747

4848
_, err := suite.srcMongoClient.
49-
Database("testDb").
49+
Database(suite.DBNameForTest()).
5050
Collection("testColl").
5151
InsertOne(
5252
ctx,
5353
bson.D{{"_id", "heyhey"}},
5454
)
5555
suite.Require().NoError(err)
5656

57-
verifier2 := buildVerifier(suite.T(), suite.srcMongoInstance, suite.dstMongoInstance, suite.metaMongoInstance)
57+
verifier2 := suite.BuildVerifier()
5858

5959
suite.Require().Empty(
6060
suite.fetchVerifierRechecks(ctx, verifier2),
@@ -89,7 +89,7 @@ func (suite *MultiSourceVersionTestSuite) TestChangeStreamResumability() {
8989

9090
suite.Assert().Equal(
9191
bson.M{
92-
"db": "testDb",
92+
"db": suite.DBNameForTest(),
9393
"coll": "testColl",
9494
"generation": int32(0),
9595
"docID": "heyhey",
@@ -99,7 +99,7 @@ func (suite *MultiSourceVersionTestSuite) TestChangeStreamResumability() {
9999
)
100100
}
101101

102-
func (suite *MultiSourceVersionTestSuite) getClusterTime(ctx context.Context, client *mongo.Client) primitive.Timestamp {
102+
func (suite *IntegrationTestSuite) getClusterTime(ctx context.Context, client *mongo.Client) primitive.Timestamp {
103103
sess, err := client.StartSession()
104104
suite.Require().NoError(err, "should start session")
105105

@@ -112,7 +112,7 @@ func (suite *MultiSourceVersionTestSuite) getClusterTime(ctx context.Context, cl
112112
return newTime
113113
}
114114

115-
func (suite *MultiSourceVersionTestSuite) fetchVerifierRechecks(ctx context.Context, verifier *Verifier) []bson.M {
115+
func (suite *IntegrationTestSuite) fetchVerifierRechecks(ctx context.Context, verifier *Verifier) []bson.M {
116116
recheckDocs := []bson.M{}
117117

118118
recheckColl := verifier.verificationDatabase().Collection(recheckQueue)
@@ -126,8 +126,8 @@ func (suite *MultiSourceVersionTestSuite) fetchVerifierRechecks(ctx context.Cont
126126
return recheckDocs
127127
}
128128

129-
func (suite *MultiSourceVersionTestSuite) TestStartAtTimeNoChanges() {
130-
verifier := buildVerifier(suite.T(), suite.srcMongoInstance, suite.dstMongoInstance, suite.metaMongoInstance)
129+
func (suite *IntegrationTestSuite) TestStartAtTimeNoChanges() {
130+
verifier := suite.BuildVerifier()
131131
ctx, cancel := context.WithCancel(context.Background())
132132
defer cancel()
133133
sess, err := suite.srcMongoClient.StartSession()
@@ -146,8 +146,12 @@ func (suite *MultiSourceVersionTestSuite) TestStartAtTimeNoChanges() {
146146
suite.Require().Equal(verifier.srcStartAtTs, origStartTs)
147147
}
148148

149-
func (suite *MultiSourceVersionTestSuite) TestStartAtTimeWithChanges() {
150-
verifier := buildVerifier(suite.T(), suite.srcMongoInstance, suite.dstMongoInstance, suite.metaMongoInstance)
149+
func (suite *IntegrationTestSuite) TestStartAtTimeWithChanges() {
150+
if suite.GetSrcTopology() == TopologySharded {
151+
suite.T().Skip("Skipping pending REP-5299.")
152+
}
153+
154+
verifier := suite.BuildVerifier()
151155
ctx, cancel := context.WithCancel(context.Background())
152156
defer cancel()
153157
sess, err := suite.srcMongoClient.StartSession()
@@ -156,11 +160,13 @@ func (suite *MultiSourceVersionTestSuite) TestStartAtTimeWithChanges() {
156160
_, err = suite.srcMongoClient.Database("testDb").Collection("testColl").InsertOne(
157161
sctx, bson.D{{"_id", 0}})
158162
suite.Require().NoError(err)
159-
origStartTs := sess.OperationTime()
160-
suite.Require().NotNil(origStartTs)
163+
164+
origSessionTime := sess.OperationTime()
165+
suite.Require().NotNil(origSessionTime)
161166
err = verifier.StartChangeStream(ctx)
162167
suite.Require().NoError(err)
163-
suite.Require().Equal(verifier.srcStartAtTs, origStartTs)
168+
suite.Require().Equal(verifier.srcStartAtTs, origSessionTime)
169+
164170
_, err = suite.srcMongoClient.Database("testDb").Collection("testColl").InsertOne(
165171
sctx, bson.D{{"_id", 1}})
166172
suite.Require().NoError(err)
@@ -173,16 +179,26 @@ func (suite *MultiSourceVersionTestSuite) TestStartAtTimeWithChanges() {
173179
_, err = suite.srcMongoClient.Database("testDb").Collection("testColl").DeleteOne(
174180
sctx, bson.D{{"_id", 1}})
175181
suite.Require().NoError(err)
176-
newStartTs := sess.OperationTime()
177-
suite.Require().NotNil(newStartTs)
178-
suite.Require().Negative(origStartTs.Compare(*newStartTs))
182+
183+
postEventsSessionTime := sess.OperationTime()
184+
suite.Require().NotNil(postEventsSessionTime)
185+
suite.Require().Negative(
186+
origSessionTime.Compare(*postEventsSessionTime),
187+
"session time after events should exceed the original",
188+
)
189+
179190
verifier.changeStreamEnderChan <- struct{}{}
180191
<-verifier.changeStreamDoneChan
181-
suite.Require().Equal(verifier.srcStartAtTs, newStartTs)
192+
193+
suite.Assert().GreaterOrEqual(
194+
verifier.srcStartAtTs.Compare(*postEventsSessionTime),
195+
0,
196+
"verifier.srcStartAtTs should now meet or exceed our session timestamp",
197+
)
182198
}
183199

184-
func (suite *MultiSourceVersionTestSuite) TestNoStartAtTime() {
185-
verifier := buildVerifier(suite.T(), suite.srcMongoInstance, suite.dstMongoInstance, suite.metaMongoInstance)
200+
func (suite *IntegrationTestSuite) TestNoStartAtTime() {
201+
verifier := suite.BuildVerifier()
186202
ctx, cancel := context.WithCancel(context.Background())
187203
defer cancel()
188204
sess, err := suite.srcMongoClient.StartSession()
@@ -199,8 +215,9 @@ func (suite *MultiSourceVersionTestSuite) TestNoStartAtTime() {
199215
suite.Require().LessOrEqual(origStartTs.Compare(*verifier.srcStartAtTs), 0)
200216
}
201217

202-
func (suite *MultiSourceVersionTestSuite) TestWithChangeEventsBatching() {
203-
verifier := buildVerifier(suite.T(), suite.srcMongoInstance, suite.dstMongoInstance, suite.metaMongoInstance)
218+
func (suite *IntegrationTestSuite) TestWithChangeEventsBatching() {
219+
verifier := suite.BuildVerifier()
220+
204221
ctx, cancel := context.WithCancel(context.Background())
205222
defer cancel()
206223

0 commit comments

Comments
 (0)