@@ -24,44 +24,154 @@ func TestSDAMErrorHandling(t *testing.T) {
24
24
SetRetryWrites (false ).
25
25
SetPoolMonitor (poolMonitor ).
26
26
SetWriteConcern (mtest .MajorityWc )
27
- mtOpts := mtest .NewOptions ().
28
- Topologies (mtest .ReplicaSet ). // Don't run on sharded clusters to avoid complexity of sharded failpoints.
29
- MinServerVersion ("4.0" ). // 4.0+ is required to use failpoints on replica sets.
30
- ClientOptions (clientOpts )
31
-
32
- mt .RunOpts ("network errors" , mtOpts , func (mt * mtest.T ) {
33
- mt .Run ("pool cleared on non-timeout network error" , func (mt * mtest.T ) {
34
- clearPoolChan ()
35
- mt .SetFailPoint (mtest.FailPoint {
36
- ConfigureFailPoint : "failCommand" ,
37
- Mode : mtest.FailPointMode {
38
- Times : 1 ,
39
- },
40
- Data : mtest.FailPointData {
41
- FailCommands : []string {"insert" },
42
- CloseConnection : true ,
43
- },
27
+ baseMtOpts := func () * mtest.Options {
28
+ mtOpts := mtest .NewOptions ().
29
+ Topologies (mtest .ReplicaSet ). // Don't run on sharded clusters to avoid complexity of sharded failpoints.
30
+ MinServerVersion ("4.0" ). // 4.0+ is required to use failpoints on replica sets.
31
+ ClientOptions (clientOpts )
32
+
33
+ if mt .TopologyKind () == mtest .Sharded {
34
+ // Pin to a single mongos because the tests use failpoints.
35
+ mtOpts .ClientType (mtest .Pinned )
36
+ }
37
+ return mtOpts
38
+ }
39
+
40
+ // Set min server version of 4.4 because the during-handshake tests use failpoint features introduced in 4.4 like
41
+ // blockConnection and appName.
42
+ mt .RunOpts ("before handshake completes" , baseMtOpts ().Auth (true ).MinServerVersion ("4.4" ), func (mt * mtest.T ) {
43
+ mt .RunOpts ("network errors" , noClientOpts , func (mt * mtest.T ) {
44
+ mt .Run ("pool cleared on network timeout" , func (mt * mtest.T ) {
45
+ // Assert that the pool is cleared when a connection created by an application operation thread
46
+ // encounters a network timeout during handshaking. Unlike the non-timeout test below, we only test
47
+ // connections created in the foreground for timeouts because connections created by the pool
48
+ // maintenance routine can't be timed out using a context.
49
+
50
+ appName := "authNetworkTimeoutTest"
51
+ // Set failpoint on saslContinue instead of saslStart because saslStart isn't done when using
52
+ // speculative auth.
53
+ mt .SetFailPoint (mtest.FailPoint {
54
+ ConfigureFailPoint : "failCommand" ,
55
+ Mode : mtest.FailPointMode {
56
+ Times : 1 ,
57
+ },
58
+ Data : mtest.FailPointData {
59
+ FailCommands : []string {"saslContinue" },
60
+ BlockConnection : true ,
61
+ BlockTimeMS : 150 ,
62
+ AppName : appName ,
63
+ },
64
+ })
65
+
66
+ // Reset the client with the appName specified in the failpoint.
67
+ clientOpts := options .Client ().
68
+ SetAppName (appName ).
69
+ SetRetryWrites (false ).
70
+ SetPoolMonitor (poolMonitor )
71
+ mt .ResetClient (clientOpts )
72
+ clearPoolChan ()
73
+
74
+ // The saslContinue blocks for 150ms so run the InsertOne with a 100ms context to cause a network
75
+ // timeout during auth and assert that the pool was cleared.
76
+ timeoutCtx , cancel := context .WithTimeout (mtest .Background , 100 * time .Millisecond )
77
+ defer cancel ()
78
+ _ , err := mt .Coll .InsertOne (timeoutCtx , bson.D {{"test" , 1 }})
79
+ assert .NotNil (mt , err , "expected InsertOne error, got nil" )
80
+ assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
44
81
})
82
+ mt .RunOpts ("pool cleared on non-timeout network error" , noClientOpts , func (mt * mtest.T ) {
83
+ mt .Run ("background" , func (mt * mtest.T ) {
84
+ // Assert that the pool is cleared when a connection created by the background pool maintenance
85
+ // routine encounters a non-timeout network error during handshaking.
86
+ appName := "authNetworkErrorTestBackground"
87
+
88
+ mt .SetFailPoint (mtest.FailPoint {
89
+ ConfigureFailPoint : "failCommand" ,
90
+ Mode : mtest.FailPointMode {
91
+ Times : 1 ,
92
+ },
93
+ Data : mtest.FailPointData {
94
+ FailCommands : []string {"saslContinue" },
95
+ CloseConnection : true ,
96
+ AppName : appName ,
97
+ },
98
+ })
99
+
100
+ clientOpts := options .Client ().
101
+ SetAppName (appName ).
102
+ SetMinPoolSize (5 ).
103
+ SetPoolMonitor (poolMonitor )
104
+ mt .ResetClient (clientOpts )
105
+ clearPoolChan ()
106
+
107
+ time .Sleep (200 * time .Millisecond )
108
+ assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
109
+ })
110
+ mt .Run ("foreground" , func (mt * mtest.T ) {
111
+ // Assert that the pool is cleared when a connection created by an application thread connection
112
+ // checkout encounters a non-timeout network error during handshaking.
113
+ appName := "authNetworkErrorTestForeground"
45
114
46
- _ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"test" , 1 }})
47
- assert .NotNil (mt , err , "expected InsertOne error, got nil" )
48
- assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
115
+ mt .SetFailPoint (mtest.FailPoint {
116
+ ConfigureFailPoint : "failCommand" ,
117
+ Mode : mtest.FailPointMode {
118
+ Times : 1 ,
119
+ },
120
+ Data : mtest.FailPointData {
121
+ FailCommands : []string {"saslContinue" },
122
+ CloseConnection : true ,
123
+ AppName : appName ,
124
+ },
125
+ })
126
+
127
+ clientOpts := options .Client ().
128
+ SetAppName (appName ).
129
+ SetPoolMonitor (poolMonitor )
130
+ mt .ResetClient (clientOpts )
131
+ clearPoolChan ()
132
+
133
+ _ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
134
+ assert .NotNil (mt , err , "expected InsertOne error, got nil" )
135
+ assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
136
+ })
137
+ })
49
138
})
50
- mt .Run ("pool not cleared on timeout network error" , func (mt * mtest.T ) {
51
- clearPoolChan ()
139
+ })
140
+ mt .RunOpts ("after handshake completes" , baseMtOpts (), func (mt * mtest.T ) {
141
+ mt .RunOpts ("network errors" , noClientOpts , func (mt * mtest.T ) {
142
+ mt .Run ("pool cleared on non-timeout network error" , func (mt * mtest.T ) {
143
+ clearPoolChan ()
144
+ mt .SetFailPoint (mtest.FailPoint {
145
+ ConfigureFailPoint : "failCommand" ,
146
+ Mode : mtest.FailPointMode {
147
+ Times : 1 ,
148
+ },
149
+ Data : mtest.FailPointData {
150
+ FailCommands : []string {"insert" },
151
+ CloseConnection : true ,
152
+ },
153
+ })
52
154
53
- _ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
54
- assert .Nil (mt , err , "InsertOne error: %v" , err )
155
+ _ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"test" , 1 }})
156
+ assert .NotNil (mt , err , "expected InsertOne error, got nil" )
157
+ assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
158
+ })
159
+ mt .Run ("pool not cleared on timeout network error" , func (mt * mtest.T ) {
160
+ clearPoolChan ()
161
+
162
+ _ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
163
+ assert .Nil (mt , err , "InsertOne error: %v" , err )
55
164
56
- filter := bson.M {
57
- "$where" : "function() { sleep(1000); return false; }" ,
58
- }
59
- timeoutCtx , cancel := context .WithTimeout (mtest .Background , 100 * time .Millisecond )
60
- defer cancel ()
61
- _ , err = mt .Coll .Find (timeoutCtx , filter )
62
- assert .NotNil (mt , err , "expected Find error, got %v" , err )
165
+ filter := bson.M {
166
+ "$where" : "function() { sleep(1000); return false; }" ,
167
+ }
168
+ timeoutCtx , cancel := context .WithTimeout (mtest .Background , 100 * time .Millisecond )
169
+ defer cancel ()
170
+ _ , err = mt .Coll .Find (timeoutCtx , filter )
171
+ assert .NotNil (mt , err , "expected Find error, got %v" , err )
63
172
64
- assert .False (mt , isPoolCleared (), "expected pool to not be cleared but was" )
173
+ assert .False (mt , isPoolCleared (), "expected pool to not be cleared but was" )
174
+ })
65
175
})
66
176
})
67
177
}
0 commit comments