Skip to content

Commit 5367196

Browse files
author
Isabella Siu
committed
GODRIVER-151 change handling of network errors or timeouts during connection handshake
Change-Id: Ic43a7cd77a9249c802820f561f565f9ebac35b2c
1 parent 4eea942 commit 5367196

File tree

4 files changed

+123
-13
lines changed

4 files changed

+123
-13
lines changed

core/topology/connection.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ func (sc *sconn) processErr(err error) {
5353
if cerr, ok := err.(command.Error); ok && (isRecoveringError(cerr) || isNotMasterError(cerr)) {
5454
desc := sc.s.Description()
5555
desc.Kind = description.Unknown
56-
57-
// updates description to unknown and clears the connection pool
56+
desc.LastError = err
57+
// updates description to unknown
5858
sc.s.updateDescription(desc, false)
5959
}
6060

@@ -70,7 +70,11 @@ func (sc *sconn) processErr(err error) {
7070
return
7171
}
7272

73-
_ = sc.s.Drain()
73+
desc := sc.s.Description()
74+
desc.Kind = description.Unknown
75+
desc.LastError = err
76+
// updates description to unknown
77+
sc.s.updateDescription(desc, false)
7478
}
7579

7680
func isRecoveringError(err command.Error) bool {

core/topology/connection_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package topology
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/mongodb/mongo-go-driver/core/address"
8+
"github.com/mongodb/mongo-go-driver/core/connection"
9+
"github.com/mongodb/mongo-go-driver/core/description"
10+
"github.com/mongodb/mongo-go-driver/core/wiremessage"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
type netErr struct {
15+
}
16+
17+
func (n netErr) Error() string {
18+
return "error"
19+
}
20+
21+
func (n netErr) Timeout() bool {
22+
return false
23+
}
24+
25+
func (n netErr) Temporary() bool {
26+
return false
27+
}
28+
29+
type connect struct {
30+
err *connection.NetworkError
31+
}
32+
33+
func (c connect) WriteWireMessage(ctx context.Context, wm wiremessage.WireMessage) error {
34+
return *c.err
35+
}
36+
func (c connect) ReadWireMessage(ctx context.Context) (wiremessage.WireMessage, error) {
37+
return nil, *c.err
38+
}
39+
func (c connect) Close() error {
40+
return nil
41+
}
42+
func (c connect) Alive() bool {
43+
return true
44+
}
45+
func (c connect) Expired() bool {
46+
return false
47+
}
48+
func (c connect) ID() string {
49+
return ""
50+
}
51+
52+
// Test case for sconn processErr
53+
func TestConnectionProcessErrSpec(t *testing.T) {
54+
ctx := context.Background()
55+
s, err := NewServer(address.Address("localhost"))
56+
require.NoError(t, err)
57+
58+
desc := s.Description()
59+
require.Nil(t, desc.LastError)
60+
61+
s.connectionstate = connected
62+
63+
innerErr := netErr{}
64+
connectErr := connection.NetworkError{"blah", innerErr}
65+
c := connect{&connectErr}
66+
sc := sconn{c, s, 1}
67+
err = sc.WriteWireMessage(ctx, nil)
68+
require.NotNil(t, err)
69+
desc = s.Description()
70+
require.NotNil(t, desc.LastError)
71+
require.Equal(t, desc.Kind, (description.ServerKind)(description.Unknown))
72+
}

core/topology/server.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,16 @@ func (s *Server) Connection(ctx context.Context) (connection.Connection, error)
182182
// authentication error --> drain connection
183183
_ = s.pool.Drain()
184184
}
185+
if _, ok := err.(*connection.NetworkError); ok {
186+
// update description to unknown and clears the connection pool
187+
if desc != nil {
188+
desc.Kind = description.Unknown
189+
desc.LastError = err
190+
s.updateDescription(*desc, false)
191+
} else {
192+
_ = s.pool.Drain()
193+
}
194+
}
185195
return nil, err
186196
}
187197
if desc != nil {

core/topology/server_test.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package topology
88

99
import (
1010
"context"
11+
"sync/atomic"
1112
"testing"
1213

1314
"github.com/mongodb/mongo-go-driver/core/address"
@@ -19,14 +20,19 @@ import (
1920

2021
type pool struct {
2122
connectionError bool
22-
drainCalled bool
23+
drainCalled atomic.Value
24+
networkError bool
25+
desc *description.Server
2326
}
2427

2528
func (p *pool) Get(ctx context.Context) (connection.Connection, *description.Server, error) {
2629
if p.connectionError {
27-
return nil, nil, &auth.Error{}
30+
return nil, p.desc, &auth.Error{}
2831
}
29-
return nil, nil, nil
32+
if p.networkError {
33+
return nil, p.desc, &connection.NetworkError{}
34+
}
35+
return nil, p.desc, nil
3036
}
3137

3238
func (p *pool) Connect(ctx context.Context) error {
@@ -38,43 +44,61 @@ func (p *pool) Disconnect(ctx context.Context) error {
3844
}
3945

4046
func (p *pool) Drain() error {
41-
p.drainCalled = true
47+
p.drainCalled.Store(true)
4248
return nil
4349
}
4450

45-
func NewPool(connectionError bool) (connection.Pool, error) {
51+
func NewPool(connectionError bool, networkError bool, desc *description.Server) (connection.Pool, error) {
4652
p := &pool{
4753
connectionError: connectionError,
54+
networkError: networkError,
55+
desc: desc,
4856
}
57+
p.drainCalled.Store(false)
4958
return p, nil
5059
}
5160

5261
func TestSever(t *testing.T) {
5362
var serverTestTable = []struct {
5463
name string
5564
connectionError bool
65+
networkError bool
66+
hasDesc bool
5667
}{
57-
{"auth_error", true},
58-
{"auth_no_error", false},
68+
{"auth_error", true, false, false},
69+
{"no_error", false, false, false},
70+
{"network_error_no_desc", false, true, false},
71+
{"network_error_desc", false, true, true},
5972
}
6073

6174
for _, tt := range serverTestTable {
6275
t.Run(tt.name, func(t *testing.T) {
6376
s, err := NewServer(address.Address("localhost"))
6477
require.NoError(t, err)
6578

66-
s.pool, err = NewPool(tt.connectionError)
79+
var desc *description.Server
80+
descript := s.Description()
81+
if tt.hasDesc {
82+
desc = &descript
83+
require.Nil(t, desc.LastError)
84+
}
85+
s.pool, err = NewPool(tt.connectionError, tt.networkError, desc)
6786
s.connectionstate = connected
6887

6988
_, err = s.Connection(context.Background())
7089

71-
if tt.connectionError {
90+
if tt.connectionError || tt.networkError {
7291
require.Error(t, err)
7392
} else {
7493
require.NoError(t, err)
7594
}
7695

77-
require.Equal(t, s.pool.(*pool).drainCalled, tt.connectionError)
96+
if tt.hasDesc {
97+
require.Equal(t, desc.Kind, (description.ServerKind)(description.Unknown))
98+
require.NotNil(t, desc.LastError)
99+
}
100+
drained := s.pool.(*pool).drainCalled.Load().(bool)
101+
require.Equal(t, drained, tt.connectionError || tt.networkError)
78102
})
79103
}
80104
}

0 commit comments

Comments
 (0)