...
1description: cursors are correctly pinned to connections for load-balanced clusters
2
3schemaVersion: '1.3'
4
5runOnRequirements:
6 - topologies: [ load-balanced ]
7
8createEntities:
9 - client:
10 id: &client0 client0
11 useMultipleMongoses: true
12 observeEvents:
13 - commandStartedEvent
14 - commandSucceededEvent
15 - commandFailedEvent
16 - connectionReadyEvent
17 - connectionClosedEvent
18 - connectionCheckedOutEvent
19 - connectionCheckedInEvent
20 - database:
21 id: &database0 database0
22 client: *client0
23 databaseName: &database0Name database0Name
24 - collection:
25 id: &collection0 collection0
26 database: *database0
27 collectionName: &collection0Name coll0
28 - collection:
29 id: &collection1 collection1
30 database: *database0
31 collectionName: &collection1Name coll1
32 - collection:
33 id: &collection2 collection2
34 database: *database0
35 collectionName: &collection2Name coll2
36
37initialData:
38 - collectionName: *collection0Name
39 databaseName: *database0Name
40 documents:
41 - { _id: 1 }
42 - { _id: 2 }
43 - { _id: 3 }
44 - collectionName: *collection1Name
45 databaseName: *database0Name
46 documents: []
47 - collectionName: *collection2Name
48 databaseName: *database0Name
49 documents: []
50
51tests:
52 - description: no connection is pinned if all documents are returned in the initial batch
53 operations:
54 - name: createFindCursor
55 object: *collection0
56 arguments:
57 filter: {}
58 saveResultAsEntity: &cursor0 cursor0
59 - &assertConnectionNotPinned
60 name: assertNumberConnectionsCheckedOut
61 object: testRunner
62 arguments:
63 client: *client0
64 connections: 0
65 expectEvents:
66 - client: *client0
67 events:
68 - commandStartedEvent:
69 command:
70 find: *collection0Name
71 filter: {}
72 commandName: find
73 - commandSucceededEvent:
74 reply:
75 cursor:
76 id: 0
77 firstBatch: { $$type: array }
78 ns: { $$type: string }
79 commandName: find
80 - client: *client0
81 eventType: cmap
82 events:
83 - connectionReadyEvent: {}
84 - connectionCheckedOutEvent: {}
85 - connectionCheckedInEvent: {}
86
87 - description: pinned connections are returned when the cursor is drained
88 operations:
89 - &createAndSaveCursor
90 name: createFindCursor
91 object: *collection0
92 arguments:
93 filter: {}
94 batchSize: 2
95 saveResultAsEntity: &cursor0 cursor0
96 - &assertConnectionPinned
97 name: assertNumberConnectionsCheckedOut
98 object: testRunner
99 arguments:
100 client: *client0
101 connections: 1
102 - name: iterateUntilDocumentOrError
103 object: *cursor0
104 expectResult: { _id: 1 }
105 - name: iterateUntilDocumentOrError
106 object: *cursor0
107 expectResult: { _id: 2 }
108 - name: iterateUntilDocumentOrError
109 object: *cursor0
110 expectResult: { _id: 3 }
111 - *assertConnectionNotPinned
112 - &closeCursor
113 name: close
114 object: *cursor0
115 expectEvents:
116 - client: *client0
117 events:
118 - &findWithBatchSizeStarted
119 commandStartedEvent:
120 command:
121 find: *collection0Name
122 filter: {}
123 batchSize: 2
124 commandName: find
125 - &findWithBatchSizeSucceeded
126 commandSucceededEvent:
127 reply:
128 cursor:
129 id: { $$type: long }
130 firstBatch: { $$type: array }
131 ns: { $$type: string }
132 commandName: find
133 - &getMoreStarted
134 commandStartedEvent:
135 command:
136 getMore: { $$type: long }
137 collection: *collection0Name
138 commandName: getMore
139 - &getMoreSucceeded
140 commandSucceededEvent:
141 reply:
142 cursor:
143 id: 0
144 ns: { $$type: string }
145 nextBatch: { $$type: array }
146 commandName: getMore
147 - client: *client0
148 eventType: cmap
149 events:
150 - connectionReadyEvent: {}
151 - connectionCheckedOutEvent: {}
152 - connectionCheckedInEvent: {}
153
154 - description: pinned connections are returned to the pool when the cursor is closed
155 operations:
156 - *createAndSaveCursor
157 - *assertConnectionPinned
158 - *closeCursor
159 - *assertConnectionNotPinned
160 expectEvents:
161 - client: *client0
162 events:
163 - *findWithBatchSizeStarted
164 - *findWithBatchSizeSucceeded
165 - &killCursorsStarted
166 commandStartedEvent:
167 commandName: killCursors
168 - &killCursorsSucceeded
169 commandSucceededEvent:
170 commandName: killCursors
171 - client: *client0
172 eventType: cmap
173 events:
174 - connectionReadyEvent: {}
175 - connectionCheckedOutEvent: {}
176 - connectionCheckedInEvent: {}
177
178 # If a network error occurs during a getMore request, the connection must remain pinned. and drivers must not
179 # attempt to send a killCursors command when the cursor is closed because the connection is no longer valid.
180 - description: pinned connections are not returned after an network error during getMore
181 operations:
182 - name: failPoint
183 object: testRunner
184 arguments:
185 client: *client0
186 failPoint:
187 configureFailPoint: failCommand
188 mode: { times: 1 }
189 data:
190 failCommands: [ getMore ]
191 closeConnection: true
192 - *createAndSaveCursor
193 - *assertConnectionPinned
194 - name: iterateUntilDocumentOrError
195 object: *cursor0
196 expectResult:
197 _id: 1
198 - name: iterateUntilDocumentOrError
199 object: *cursor0
200 expectResult:
201 _id: 2
202 # Third next() call should perform a getMore.
203 - name: iterateUntilDocumentOrError
204 object: *cursor0
205 expectError:
206 # Network errors are considered client-side errors per the unified test format spec.
207 isClientError: true
208 - *assertConnectionPinned
209 - *closeCursor # Execute a close operation to actually release the connection.
210 - *assertConnectionNotPinned
211 expectEvents:
212 - client: *client0
213 events:
214 - *findWithBatchSizeStarted
215 - *findWithBatchSizeSucceeded
216 - *getMoreStarted
217 - &getMoreFailed
218 commandFailedEvent:
219 commandName: getMore
220 - client: *client0
221 eventType: cmap
222 events:
223 # Events to set the failpoint.
224 - connectionReadyEvent: {}
225 - connectionCheckedOutEvent: {}
226 - connectionCheckedInEvent: {}
227 # Events for the find command + getMore.
228 - connectionCheckedOutEvent: {}
229 # Events for the close() operation.
230 - connectionCheckedInEvent: {}
231 - connectionClosedEvent:
232 reason: error
233
234 - description: pinned connections are returned after a network error during a killCursors request
235 operations:
236 - name: failPoint
237 object: testRunner
238 arguments:
239 client: *client0
240 failPoint:
241 configureFailPoint: failCommand
242 mode: { times: 1 }
243 data:
244 failCommands: [ killCursors ]
245 closeConnection: true
246 - *createAndSaveCursor
247 - *assertConnectionPinned
248 - *closeCursor
249 - *assertConnectionNotPinned
250 expectEvents:
251 - client: *client0
252 events:
253 - *findWithBatchSizeStarted
254 - *findWithBatchSizeSucceeded
255 - *killCursorsStarted
256 - commandFailedEvent:
257 commandName: killCursors
258 - client: *client0
259 eventType: cmap
260 events:
261 # Events to set the failpoint.
262 - connectionReadyEvent: {}
263 - connectionCheckedOutEvent: {}
264 - connectionCheckedInEvent: {}
265 # Events for the find command + killCursors.
266 - connectionCheckedOutEvent: {}
267 - connectionCheckedInEvent: {}
268 - connectionClosedEvent:
269 reason: error
270
271 - description: pinned connections are not returned to the pool after a non-network error on getMore
272 operations:
273 - name: failPoint
274 object: testRunner
275 arguments:
276 client: *client0
277 failPoint:
278 configureFailPoint: failCommand
279 mode: { times: 1 }
280 data:
281 failCommands: [ getMore ]
282 errorCode: &hostNotFoundCode 7 # This is not a state change error code, so it should not cause SDAM changes.
283 - *createAndSaveCursor
284 - name: iterateUntilDocumentOrError
285 object: *cursor0
286 expectResult:
287 _id: 1
288 - name: iterateUntilDocumentOrError
289 object: *cursor0
290 expectResult:
291 _id: 2
292 - name: iterateUntilDocumentOrError
293 object: *cursor0
294 expectError:
295 errorCode: *hostNotFoundCode
296 - *assertConnectionPinned
297 - *closeCursor
298 - *assertConnectionNotPinned
299 expectEvents:
300 - client: *client0
301 events:
302 - *findWithBatchSizeStarted
303 - *findWithBatchSizeSucceeded
304 - *getMoreStarted
305 - *getMoreFailed
306 - *killCursorsStarted
307 - *killCursorsSucceeded
308 - client: *client0
309 eventType: cmap
310 events:
311 # Events to set the failpoint.
312 - connectionReadyEvent: {}
313 - connectionCheckedOutEvent: {}
314 - connectionCheckedInEvent: {}
315 # Events for the find command + getMore + killCursors.
316 - connectionCheckedOutEvent: {}
317 - connectionCheckedInEvent: {}
318
319 # Basic tests for cursor-creating commands besides "find". We don't need to replicate the full set of tests defined
320 # above for each such command. Instead, only one test is needed per command to ensure that the pinned connection is
321 # correctly passed down to the server.
322 #
323 # Each test creates a cursor with a small batch size and fully iterates it. Because drivers do not publish CMAP
324 # events when using pinned connections, each test asserts that only one set of ready/checkout/checkin events are
325 # published.
326
327 - description: aggregate pins the cursor to a connection
328 operations:
329 - name: aggregate
330 object: *collection0
331 arguments:
332 pipeline: []
333 batchSize: 2
334 - name: assertNumberConnectionsCheckedOut
335 object: testRunner
336 arguments:
337 client: *client0
338 connections: 0
339 expectEvents:
340 - client: *client0
341 events:
342 - commandStartedEvent:
343 command:
344 aggregate: *collection0Name
345 cursor:
346 batchSize: 2
347 commandName: aggregate
348 - commandSucceededEvent:
349 commandName: aggregate
350 - *getMoreStarted
351 - *getMoreSucceeded
352 - client: *client0
353 eventType: cmap
354 events:
355 - connectionReadyEvent: {}
356 - connectionCheckedOutEvent: {}
357 - connectionCheckedInEvent: {}
358
359 - description: listCollections pins the cursor to a connection
360 runOnRequirements:
361 - serverless: forbid # CLOUDP-98562 listCollections batchSize is ignored on serverless.
362 operations:
363 - name: listCollections
364 object: *database0
365 arguments:
366 filter: {}
367 batchSize: 2
368 - name: assertNumberConnectionsCheckedOut
369 object: testRunner
370 arguments:
371 client: *client0
372 connections: 0
373 expectEvents:
374 - client: *client0
375 events:
376 - commandStartedEvent:
377 command:
378 listCollections: 1
379 cursor:
380 batchSize: 2
381 commandName: listCollections
382 databaseName: *database0Name
383 - commandSucceededEvent:
384 commandName: listCollections
385 # Write out the event for getMore rather than using the getMoreStarted anchor because the "collection" field
386 # is not equal to *collection0Name as the command is not executed against a collection.
387 - commandStartedEvent:
388 command:
389 getMore: { $$type: long }
390 collection: { $$type: string }
391 commandName: getMore
392 - *getMoreSucceeded
393 - client: *client0
394 eventType: cmap
395 events:
396 - connectionReadyEvent: {}
397 - connectionCheckedOutEvent: {}
398 - connectionCheckedInEvent: {}
399
400 - description: listIndexes pins the cursor to a connection
401 operations:
402 # There is an automatic index on _id so we create two more indexes to force multiple batches with batchSize=2.
403 - name: createIndex
404 object: *collection0
405 arguments:
406 keys: &x1IndexSpec { x: 1 }
407 name: &x1IndexName x_1
408 - name: createIndex
409 object: *collection0
410 arguments:
411 keys: &y1IndexSpec { y: 1 }
412 name: &y1IndexName y_1
413 - name: listIndexes
414 object: *collection0
415 arguments:
416 batchSize: 2
417 - name: assertNumberConnectionsCheckedOut
418 object: testRunner
419 arguments:
420 client: *client0
421 connections: 0
422 expectEvents:
423 - client: *client0
424 events:
425 - commandStartedEvent:
426 command:
427 createIndexes: *collection0Name
428 indexes:
429 - name: *x1IndexName
430 key: *x1IndexSpec
431 commandName: createIndexes
432 - commandSucceededEvent:
433 commandName: createIndexes
434 - commandStartedEvent:
435 command:
436 createIndexes: *collection0Name
437 indexes:
438 - name: *y1IndexName
439 key: *y1IndexSpec
440 commandName: createIndexes
441 - commandSucceededEvent:
442 commandName: createIndexes
443 - commandStartedEvent:
444 command:
445 listIndexes: *collection0Name
446 cursor:
447 batchSize: 2
448 commandName: listIndexes
449 databaseName: *database0Name
450 - commandSucceededEvent:
451 commandName: listIndexes
452 - *getMoreStarted
453 - *getMoreSucceeded
454 - client: *client0
455 eventType: cmap
456 events:
457 # Events for first createIndexes.
458 - connectionReadyEvent: {}
459 - connectionCheckedOutEvent: {}
460 - connectionCheckedInEvent: {}
461 # Events for second createIndexes.
462 - connectionCheckedOutEvent: {}
463 - connectionCheckedInEvent: {}
464 # Events for listIndexes and getMore.
465 - connectionCheckedOutEvent: {}
466 - connectionCheckedInEvent: {}
467
468 - description: change streams pin to a connection
469 runOnRequirements:
470 - serverless: forbid # Serverless does not support change streams.
471 operations:
472 - name: createChangeStream
473 object: *collection0
474 arguments:
475 pipeline: []
476 saveResultAsEntity: &changeStream0 changeStream0
477 - name: assertNumberConnectionsCheckedOut
478 object: testRunner
479 arguments:
480 client: *client0
481 connections: 1
482 - name: close
483 object: *changeStream0
484 - name: assertNumberConnectionsCheckedOut
485 object: testRunner
486 arguments:
487 client: *client0
488 connections: 0
489 expectEvents:
490 - client: *client0
491 events:
492 - commandStartedEvent:
493 commandName: aggregate
494 - commandSucceededEvent:
495 commandName: aggregate
496 - commandStartedEvent:
497 commandName: killCursors
498 - commandSucceededEvent:
499 commandName: killCursors
500 - client: *client0
501 eventType: cmap
502 events:
503 # Events for creating the change stream.
504 - connectionReadyEvent: {}
505 - connectionCheckedOutEvent: {}
506 # Events for closing the change stream.
507 - connectionCheckedInEvent: {}
View as plain text