Skip to content

Commit e22ca8f

Browse files
authored
GODRIVER-1778 Reject HeartbeatFrequencyMS of less than 500ms (#1828)
1 parent c42db6b commit e22ca8f

File tree

6 files changed

+74
-14
lines changed

6 files changed

+74
-14
lines changed

internal/integration/client_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ type slowConnDialer struct {
7070
}
7171

7272
var slowConnDialerDelay = 300 * time.Millisecond
73-
var reducedHeartbeatInterval = 100 * time.Millisecond
73+
var reducedHeartbeatInterval = 500 * time.Millisecond
7474

7575
func newSlowConnDialer(delay time.Duration) *slowConnDialer {
7676
return &slowConnDialer{
@@ -517,7 +517,7 @@ func TestClient(t *testing.T) {
517517
mt.Parallel()
518518

519519
// Reset the client with a dialer that delays all network round trips by 300ms and set the
520-
// heartbeat interval to 100ms to reduce the time it takes to collect RTT samples.
520+
// heartbeat interval to 500ms to reduce the time it takes to collect RTT samples.
521521
mt.ResetClient(options.Client().
522522
SetDialer(newSlowConnDialer(slowConnDialerDelay)).
523523
SetHeartbeatInterval(reducedHeartbeatInterval))
@@ -555,7 +555,7 @@ func TestClient(t *testing.T) {
555555
assert.Nil(mt, err, "Ping error: %v", err)
556556

557557
// Reset the client with a dialer that delays all network round trips by 300ms and set the
558-
// heartbeat interval to 100ms to reduce the time it takes to collect RTT samples.
558+
// heartbeat interval to 500ms to reduce the time it takes to collect RTT samples.
559559
tpm := eventtest.NewTestPoolMonitor()
560560
mt.ResetClient(options.Client().
561561
SetPoolMonitor(tpm.PoolMonitor).

internal/integration/unified/unified_spec_runner.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ var (
9090
}
9191

9292
logMessageValidatorTimeout = 10 * time.Millisecond
93-
lowHeartbeatFrequency = 50 * time.Millisecond
93+
lowHeartbeatFrequency = 500 * time.Millisecond
9494
)
9595

9696
// TestCase holds and runs a unified spec test case

internal/integration/unified_spec_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const (
4646
)
4747

4848
var (
49-
defaultHeartbeatInterval = 50 * time.Millisecond
49+
defaultHeartbeatInterval = 500 * time.Millisecond
5050
skippedTestDescriptions = map[string]string{
5151
// SPEC-1403: This test checks to see if the correct error is thrown when auto encrypting with a server < 4.2.
5252
// Currently, the test will fail because a server < 4.2 wouldn't have mongocryptd, so Client construction

mongo/options/clientoptions.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,11 @@ func (c *ClientOptionsBuilder) Validate() error {
546546
}
547547
}
548548

549+
if args.HeartbeatInterval != nil && *args.HeartbeatInterval < (500*time.Millisecond) {
550+
return fmt.Errorf("heartbeatFrequencyMS must exceed the minimum heartbeat interval of 500ms, got heartbeatFrequencyMS=%q",
551+
*args.HeartbeatInterval)
552+
}
553+
549554
if args.MaxPoolSize != nil && args.MinPoolSize != nil && *args.MaxPoolSize != 0 &&
550555
*args.MinPoolSize > *args.MaxPoolSize {
551556
return fmt.Errorf("minPoolSize must be less than or equal to maxPoolSize, got minPoolSize=%d maxPoolSize=%d",
@@ -755,7 +760,8 @@ func (c *ClientOptionsBuilder) SetDirect(b bool) *ClientOptionsBuilder {
755760
}
756761

757762
// SetHeartbeatInterval specifies the amount of time to wait between periodic background server checks. This can also be
758-
// set through the "heartbeatIntervalMS" URI option (e.g. "heartbeatIntervalMS=10000"). The default is 10 seconds.
763+
// set through the "heartbeatFrequencyMS" URI option (e.g. "heartbeatFrequencyMS=10000"). The default is 10 seconds.
764+
// The minimum is 500ms.
759765
func (c *ClientOptionsBuilder) SetHeartbeatInterval(d time.Duration) *ClientOptionsBuilder {
760766
c.Opts = append(c.Opts, func(opts *ClientOptions) error {
761767
opts.HeartbeatInterval = &d

mongo/options/clientoptions_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,60 @@ func TestClientOptions(t *testing.T) {
240240
})
241241
}
242242
})
243+
t.Run("heartbeatFrequencyMS validation", func(t *testing.T) {
244+
testCases := []struct {
245+
name string
246+
opts *ClientOptionsBuilder
247+
err error
248+
}{
249+
{
250+
name: "heartbeatFrequencyMS > minimum (500ms)",
251+
opts: Client().SetHeartbeatInterval(10000 * time.Millisecond),
252+
err: nil,
253+
},
254+
{
255+
name: "heartbeatFrequencyMS == minimum (500ms)",
256+
opts: Client().SetHeartbeatInterval(500 * time.Millisecond),
257+
err: nil,
258+
},
259+
{
260+
name: "heartbeatFrequencyMS < minimum (500ms)",
261+
opts: Client().SetHeartbeatInterval(10 * time.Millisecond),
262+
err: errors.New("heartbeatFrequencyMS must exceed the minimum heartbeat interval of 500ms, got heartbeatFrequencyMS=\"10ms\""),
263+
},
264+
{
265+
name: "heartbeatFrequencyMS == 0",
266+
opts: Client().SetHeartbeatInterval(0 * time.Millisecond),
267+
err: errors.New("heartbeatFrequencyMS must exceed the minimum heartbeat interval of 500ms, got heartbeatFrequencyMS=\"0s\""),
268+
},
269+
{
270+
name: "heartbeatFrequencyMS > minimum (500ms) from URI",
271+
opts: Client().ApplyURI("mongodb://localhost:27017/?heartbeatFrequencyMS=10000"),
272+
err: nil,
273+
},
274+
{
275+
name: "heartbeatFrequencyMS == minimum (500ms) from URI",
276+
opts: Client().ApplyURI("mongodb://localhost:27017/?heartbeatFrequencyMS=500"),
277+
err: nil,
278+
},
279+
{
280+
name: "heartbeatFrequencyMS < minimum (500ms) from URI",
281+
opts: Client().ApplyURI("mongodb://localhost:27017/?heartbeatFrequencyMS=10"),
282+
err: errors.New("heartbeatFrequencyMS must exceed the minimum heartbeat interval of 500ms, got heartbeatFrequencyMS=\"10ms\""),
283+
},
284+
{
285+
name: "heartbeatFrequencyMS == 0 from URI",
286+
opts: Client().ApplyURI("mongodb://localhost:27017/?heartbeatFrequencyMS=0"),
287+
err: errors.New("heartbeatFrequencyMS must exceed the minimum heartbeat interval of 500ms, got heartbeatFrequencyMS=\"0s\""),
288+
},
289+
}
290+
for _, tc := range testCases {
291+
t.Run(tc.name, func(t *testing.T) {
292+
err := tc.opts.Validate()
293+
assert.Equal(t, tc.err, err)
294+
})
295+
}
296+
})
243297
t.Run("minPoolSize validation", func(t *testing.T) {
244298
testCases := []struct {
245299
name string

x/mongo/driver/topology/polling_srv_records_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,9 @@ func compareHosts(t *testing.T, received []description.Server, expected []string
127127

128128
func TestPollingSRVRecordsSpec(t *testing.T) {
129129
for _, uri := range []string{
130-
"mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=100",
130+
"mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=500",
131131
// Test with user:pass as a regression test for GODRIVER-2620
132-
"mongodb+srv://user:[email protected]/?heartbeatFrequencyMS=100",
132+
"mongodb+srv://user:[email protected]/?heartbeatFrequencyMS=500",
133133
} {
134134
t.Run(uri, func(t *testing.T) {
135135
testPollingSRVRecordsSpec(t, uri)
@@ -169,7 +169,7 @@ func testPollingSRVRecordsSpec(t *testing.T, uri string) {
169169

170170
func TestPollSRVRecords(t *testing.T) {
171171
t.Run("Not unknown or sharded topology", func(t *testing.T) {
172-
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=100"
172+
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=500"
173173
cfg, err := NewConfig(options.Client().ApplyURI(uri), nil)
174174
require.NoError(t, err, "error constructing topology config: %v", err)
175175

@@ -207,7 +207,7 @@ func TestPollSRVRecords(t *testing.T) {
207207

208208
})
209209
t.Run("Failed Hostname Verification", func(t *testing.T) {
210-
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=100"
210+
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=500"
211211
cfg, err := NewConfig(options.Client().ApplyURI(uri), nil)
212212
require.NoError(t, err, "error constructing topology config: %v", err)
213213

@@ -234,7 +234,7 @@ func TestPollSRVRecords(t *testing.T) {
234234

235235
})
236236
t.Run("Return to polling time", func(t *testing.T) {
237-
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=100"
237+
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=500"
238238
cfg, err := NewConfig(options.Client().ApplyURI(uri), nil)
239239
require.NoError(t, err, "error constructing topology config: %v", err)
240240

@@ -276,7 +276,7 @@ func TestPollingSRVRecordsLoadBalanced(t *testing.T) {
276276
}
277277

278278
t.Run("pollingRequired is set to false", func(t *testing.T) {
279-
topo := createLBTopology(t, "mongodb+srv://test24.test.build.10gen.cc/?heartbeatFrequencyMS=100")
279+
topo := createLBTopology(t, "mongodb+srv://test24.test.build.10gen.cc/?heartbeatFrequencyMS=500")
280280
assert.False(t, topo.pollingRequired, "expected SRV polling to not be required, but it is")
281281
})
282282

@@ -313,7 +313,7 @@ func TestPollSRVRecordsMaxHosts(t *testing.T) {
313313
simulateSRVPoll := func(srvMaxHosts int, recordsToAdd []*net.SRV, recordsToRemove []*net.SRV) (*Topology, func(ctx context.Context) error) {
314314
t.Helper()
315315

316-
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=100"
316+
uri := "mongodb+srv://test1.test.build.10gen.cc/?heartbeatFrequencyMS=500"
317317
cfg, err := NewConfig(options.Client().ApplyURI(uri).SetSRVMaxHosts(srvMaxHosts), nil)
318318
require.NoError(t, err, "error constructing topology config: %v", err)
319319

@@ -385,7 +385,7 @@ func TestPollSRVRecordsServiceName(t *testing.T) {
385385
simulateSRVPoll := func(srvServiceName string, recordsToAdd []*net.SRV, recordsToRemove []*net.SRV) (*Topology, func(ctx context.Context) error) {
386386
t.Helper()
387387

388-
uri := "mongodb+srv://test22.test.build.10gen.cc/?heartbeatFrequencyMS=100&srvServiceName=customname"
388+
uri := "mongodb+srv://test22.test.build.10gen.cc/?heartbeatFrequencyMS=500&srvServiceName=customname"
389389
cfg, err := NewConfig(options.Client().ApplyURI(uri).SetSRVServiceName(srvServiceName), nil)
390390
require.NoError(t, err, "error constructing topology config: %v", err)
391391

0 commit comments

Comments
 (0)