@@ -16,6 +16,7 @@ import (
16
16
"time"
17
17
18
18
"go.mongodb.org/mongo-driver/bson"
19
+ "go.mongodb.org/mongo-driver/event"
19
20
"go.mongodb.org/mongo-driver/internal/testutil/assert"
20
21
"go.mongodb.org/mongo-driver/mongo"
21
22
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
@@ -28,7 +29,6 @@ func TestSDAMErrorHandling(t *testing.T) {
28
29
return options .Client ().
29
30
ApplyURI (mtest .ClusterURI ()).
30
31
SetRetryWrites (false ).
31
- SetPoolMonitor (poolMonitor ).
32
32
SetWriteConcern (mtest .MajorityWc )
33
33
}
34
34
baseMtOpts := func () * mtest.Options {
@@ -71,13 +71,9 @@ func TestSDAMErrorHandling(t *testing.T) {
71
71
},
72
72
})
73
73
74
- // Reset the client with the appName specified in the failpoint.
75
- clientOpts := options .Client ().
76
- SetAppName (appName ).
77
- SetRetryWrites (false ).
78
- SetPoolMonitor (poolMonitor )
79
- mt .ResetClient (clientOpts )
80
- clearPoolChan ()
74
+ // Reset the client with the appName specified in the failpoint and the pool monitor.
75
+ tpm := newTestPoolMonitor ()
76
+ mt .ResetClient (baseClientOpts ().SetAppName (appName ).SetPoolMonitor (tpm .PoolMonitor ))
81
77
82
78
// Use a context with a 100ms timeout so that the saslContinue delay of 150ms causes
83
79
// an operation-scoped context timeout (i.e. a timeout not caused by a client timeout
@@ -88,7 +84,11 @@ func TestSDAMErrorHandling(t *testing.T) {
88
84
assert .NotNil (mt , err , "expected InsertOne error, got nil" )
89
85
assert .True (mt , mongo .IsTimeout (err ), "expected timeout error, got %v" , err )
90
86
assert .True (mt , mongo .IsNetworkError (err ), "expected network error, got %v" , err )
91
- assert .False (mt , isPoolCleared (), "expected pool not to be cleared but was cleared" )
87
+
88
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
89
+ return evt .Type == event .PoolCleared
90
+ })
91
+ assert .True (mt , len (poolClearedEvents ) == 0 , "expected pool not to be cleared but was cleared" )
92
92
})
93
93
94
94
mt .Run ("pool cleared on non-operation-scoped network timeout" , func (mt * mtest.T ) {
@@ -112,24 +112,26 @@ func TestSDAMErrorHandling(t *testing.T) {
112
112
},
113
113
})
114
114
115
- // Reset the client with the appName specified in the failpoint.
116
- clientOpts := options .Client ().
115
+ // Reset the client with the appName specified in the failpoint and the pool monitor.
116
+ tpm := newTestPoolMonitor ()
117
+ mt .ResetClient (baseClientOpts ().
117
118
SetAppName (appName ).
118
- SetRetryWrites (false ).
119
- SetPoolMonitor (poolMonitor ).
119
+ SetPoolMonitor (tpm .PoolMonitor ).
120
120
// Set a 100ms socket timeout so that the saslContinue delay of 150ms causes a
121
121
// timeout during socket read (i.e. a timeout not caused by the InsertOne context).
122
- SetSocketTimeout (100 * time .Millisecond )
123
- mt .ResetClient (clientOpts )
124
- clearPoolChan ()
122
+ SetSocketTimeout (100 * time .Millisecond ))
125
123
126
124
// Use context.Background() so that the new connection will not time out due to an
127
125
// operation-scoped timeout.
128
126
_ , err := mt .Coll .InsertOne (context .Background (), bson.D {{"test" , 1 }})
129
127
assert .NotNil (mt , err , "expected InsertOne error, got nil" )
130
128
assert .True (mt , mongo .IsTimeout (err ), "expected timeout error, got %v" , err )
131
129
assert .True (mt , mongo .IsNetworkError (err ), "expected network error, got %v" , err )
132
- assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
130
+
131
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
132
+ return evt .Type == event .PoolCleared
133
+ })
134
+ assert .True (mt , len (poolClearedEvents ) > 0 , "expected pool to be cleared but was not" )
133
135
})
134
136
135
137
mt .RunOpts ("pool cleared on non-timeout network error" , noClientOpts , func (mt * mtest.T ) {
@@ -150,15 +152,20 @@ func TestSDAMErrorHandling(t *testing.T) {
150
152
},
151
153
})
152
154
153
- clientOpts := options .Client ().
155
+ // Reset the client with the appName specified in the failpoint.
156
+ tpm := newTestPoolMonitor ()
157
+ mt .ResetClient (baseClientOpts ().
154
158
SetAppName (appName ).
155
- SetMinPoolSize (5 ).
156
- SetPoolMonitor (poolMonitor )
157
- mt .ResetClient (clientOpts )
158
- clearPoolChan ()
159
+ SetPoolMonitor (tpm .PoolMonitor ).
160
+ // Set minPoolSize to enable the background pool maintenance goroutine.
161
+ SetMinPoolSize (5 ))
159
162
160
163
time .Sleep (200 * time .Millisecond )
161
- assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
164
+
165
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
166
+ return evt .Type == event .PoolCleared
167
+ })
168
+ assert .True (mt , len (poolClearedEvents ) > 0 , "expected pool to be cleared but was not" )
162
169
})
163
170
164
171
mt .Run ("foreground" , func (mt * mtest.T ) {
@@ -178,24 +185,27 @@ func TestSDAMErrorHandling(t *testing.T) {
178
185
},
179
186
})
180
187
181
- clientOpts := options .Client ().
182
- SetAppName (appName ).
183
- SetPoolMonitor (poolMonitor )
184
- mt .ResetClient (clientOpts )
185
- clearPoolChan ()
188
+ // Reset the client with the appName specified in the failpoint.
189
+ tpm := newTestPoolMonitor ()
190
+ mt .ResetClient (baseClientOpts ().SetAppName (appName ).SetPoolMonitor (tpm .PoolMonitor ))
186
191
187
192
_ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
188
193
assert .NotNil (mt , err , "expected InsertOne error, got nil" )
189
194
assert .False (mt , mongo .IsTimeout (err ), "expected non-timeout error, got %v" , err )
190
- assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
195
+
196
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
197
+ return evt .Type == event .PoolCleared
198
+ })
199
+ assert .True (mt , len (poolClearedEvents ) > 0 , "expected pool to be cleared but was not" )
191
200
})
192
201
})
193
202
})
194
203
})
195
204
mt .RunOpts ("after handshake completes" , baseMtOpts (), func (mt * mtest.T ) {
196
205
mt .RunOpts ("network errors" , noClientOpts , func (mt * mtest.T ) {
197
206
mt .Run ("pool cleared on non-timeout network error" , func (mt * mtest.T ) {
198
- clearPoolChan ()
207
+ appName := "afterHandshakeNetworkError"
208
+
199
209
mt .SetFailPoint (mtest.FailPoint {
200
210
ConfigureFailPoint : "failCommand" ,
201
211
Mode : mtest.FailPointMode {
@@ -204,16 +214,26 @@ func TestSDAMErrorHandling(t *testing.T) {
204
214
Data : mtest.FailPointData {
205
215
FailCommands : []string {"insert" },
206
216
CloseConnection : true ,
217
+ AppName : appName ,
207
218
},
208
219
})
209
220
221
+ // Reset the client with the appName specified in the failpoint.
222
+ tpm := newTestPoolMonitor ()
223
+ mt .ResetClient (baseClientOpts ().SetAppName (appName ).SetPoolMonitor (tpm .PoolMonitor ))
224
+
210
225
_ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"test" , 1 }})
211
226
assert .NotNil (mt , err , "expected InsertOne error, got nil" )
212
227
assert .False (mt , mongo .IsTimeout (err ), "expected non-timeout error, got %v" , err )
213
- assert .True (mt , isPoolCleared (), "expected pool to be cleared but was not" )
228
+
229
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
230
+ return evt .Type == event .PoolCleared
231
+ })
232
+ assert .True (mt , len (poolClearedEvents ) > 0 , "expected pool to be cleared but was not" )
214
233
})
215
234
mt .Run ("pool not cleared on timeout network error" , func (mt * mtest.T ) {
216
- clearPoolChan ()
235
+ tpm := newTestPoolMonitor ()
236
+ mt .ResetClient (baseClientOpts ().SetPoolMonitor (tpm .PoolMonitor ))
217
237
218
238
_ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
219
239
assert .Nil (mt , err , "InsertOne error: %v" , err )
@@ -227,10 +247,14 @@ func TestSDAMErrorHandling(t *testing.T) {
227
247
assert .NotNil (mt , err , "expected Find error, got %v" , err )
228
248
assert .True (mt , mongo .IsTimeout (err ), "expected timeout error, got %v" , err )
229
249
230
- assert .False (mt , isPoolCleared (), "expected pool to not be cleared but was" )
250
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
251
+ return evt .Type == event .PoolCleared
252
+ })
253
+ assert .True (mt , len (poolClearedEvents ) == 0 , "expected pool to not be cleared but was" )
231
254
})
232
255
mt .Run ("pool not cleared on context cancellation" , func (mt * mtest.T ) {
233
- clearPoolChan ()
256
+ tpm := newTestPoolMonitor ()
257
+ mt .ResetClient (baseClientOpts ().SetPoolMonitor (tpm .PoolMonitor ))
234
258
235
259
_ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
236
260
assert .Nil (mt , err , "InsertOne error: %v" , err )
@@ -250,7 +274,10 @@ func TestSDAMErrorHandling(t *testing.T) {
250
274
assert .True (mt , mongo .IsNetworkError (err ), "expected network error, got %v" , err )
251
275
assert .True (mt , errors .Is (err , context .Canceled ), "expected error %v to be context.Canceled" , err )
252
276
253
- assert .False (mt , isPoolCleared (), "expected pool to not be cleared but was" )
277
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
278
+ return evt .Type == event .PoolCleared
279
+ })
280
+ assert .True (mt , len (poolClearedEvents ) == 0 , "expected pool to not be cleared but was" )
254
281
})
255
282
})
256
283
mt .RunOpts ("server errors" , noClientOpts , func (mt * mtest.T ) {
@@ -287,28 +314,32 @@ func TestSDAMErrorHandling(t *testing.T) {
287
314
}
288
315
for _ , tc := range testCases {
289
316
mt .RunOpts (fmt .Sprintf ("command error - %s" , tc .name ), serverErrorsMtOpts , func (mt * mtest.T ) {
290
- clearPoolChan ( )
317
+ appName := fmt . Sprintf ( "command_error_%s" , tc . name )
291
318
292
319
// Cause the next insert to fail with an ok:0 response.
293
- fp := mtest.FailPoint {
320
+ mt . SetFailPoint ( mtest.FailPoint {
294
321
ConfigureFailPoint : "failCommand" ,
295
322
Mode : mtest.FailPointMode {
296
323
Times : 1 ,
297
324
},
298
325
Data : mtest.FailPointData {
299
326
FailCommands : []string {"insert" },
300
327
ErrorCode : tc .errorCode ,
328
+ AppName : appName ,
301
329
},
302
- }
303
- mt .SetFailPoint (fp )
330
+ })
331
+
332
+ // Reset the client with the appName specified in the failpoint.
333
+ tpm := newTestPoolMonitor ()
334
+ mt .ResetClient (baseClientOpts ().SetAppName (appName ).SetPoolMonitor (tpm .PoolMonitor ))
304
335
305
- runServerErrorsTest (mt , tc .isShutdownError )
336
+ runServerErrorsTest (mt , tc .isShutdownError , tpm )
306
337
})
307
338
mt .RunOpts (fmt .Sprintf ("write concern error - %s" , tc .name ), serverErrorsMtOpts , func (mt * mtest.T ) {
308
- clearPoolChan ( )
339
+ appName := fmt . Sprintf ( "write_concern_error_%s" , tc . name )
309
340
310
341
// Cause the next insert to fail with a write concern error.
311
- fp := mtest.FailPoint {
342
+ mt . SetFailPoint ( mtest.FailPoint {
312
343
ConfigureFailPoint : "failCommand" ,
313
344
Mode : mtest.FailPointMode {
314
345
Times : 1 ,
@@ -318,32 +349,40 @@ func TestSDAMErrorHandling(t *testing.T) {
318
349
WriteConcernError : & mtest.WriteConcernErrorData {
319
350
Code : tc .errorCode ,
320
351
},
352
+ AppName : appName ,
321
353
},
322
- }
323
- mt .SetFailPoint (fp )
354
+ })
324
355
325
- runServerErrorsTest (mt , tc .isShutdownError )
356
+ // Reset the client with the appName specified in the failpoint.
357
+ tpm := newTestPoolMonitor ()
358
+ mt .ResetClient (baseClientOpts ().SetAppName (appName ).SetPoolMonitor (tpm .PoolMonitor ))
359
+
360
+ runServerErrorsTest (mt , tc .isShutdownError , tpm )
326
361
})
327
362
}
328
363
})
329
364
})
330
365
}
331
366
332
- func runServerErrorsTest (mt * mtest.T , isShutdownError bool ) {
367
+ func runServerErrorsTest (mt * mtest.T , isShutdownError bool , tpm * testPoolMonitor ) {
333
368
mt .Helper ()
334
369
335
370
_ , err := mt .Coll .InsertOne (mtest .Background , bson.D {{"x" , 1 }})
336
371
assert .NotNil (mt , err , "expected InsertOne error, got nil" )
337
372
373
+ poolClearedEvents := tpm .Events (func (evt * event.PoolEvent ) bool {
374
+ return evt .Type == event .PoolCleared
375
+ })
376
+ isPoolCleared := len (poolClearedEvents ) > 0
377
+
338
378
// The pool should always be cleared for shutdown errors, regardless of server version.
339
379
if isShutdownError {
340
- assert .True (mt , isPoolCleared () , "expected pool to be cleared, but was not" )
380
+ assert .True (mt , isPoolCleared , "expected pool to be cleared, but was not" )
341
381
return
342
382
}
343
383
344
384
// For non-shutdown errors, the pool is only cleared if the error is from a pre-4.2 server.
345
385
wantCleared := mtest .CompareServerVersions (mtest .ServerVersion (), "4.2" ) < 0
346
- gotCleared := isPoolCleared ()
347
- assert .Equal (mt , wantCleared , gotCleared , "expected pool to be cleared: %v; pool was cleared: %v" ,
348
- wantCleared , gotCleared )
386
+ assert .Equal (mt , wantCleared , isPoolCleared , "expected pool to be cleared: %t; pool was cleared: %t" ,
387
+ wantCleared , isPoolCleared )
349
388
}
0 commit comments