2025-03-17 20:58:26 +01:00

508 lines
16 KiB
YAML

description: cursors are correctly pinned to connections for load-balanced clusters
schemaVersion: '1.3'
runOnRequirements:
- topologies: [ load-balanced ]
createEntities:
- client:
id: &client0 client0
useMultipleMongoses: true
observeEvents:
- commandStartedEvent
- commandSucceededEvent
- commandFailedEvent
- connectionReadyEvent
- connectionClosedEvent
- connectionCheckedOutEvent
- connectionCheckedInEvent
- database:
id: &database0 database0
client: *client0
databaseName: &database0Name database0Name
- collection:
id: &collection0 collection0
database: *database0
collectionName: &collection0Name coll0
- collection:
id: &collection1 collection1
database: *database0
collectionName: &collection1Name coll1
- collection:
id: &collection2 collection2
database: *database0
collectionName: &collection2Name coll2
initialData:
- collectionName: *collection0Name
databaseName: *database0Name
documents:
- { _id: 1 }
- { _id: 2 }
- { _id: 3 }
- collectionName: *collection1Name
databaseName: *database0Name
documents: []
- collectionName: *collection2Name
databaseName: *database0Name
documents: []
tests:
- description: no connection is pinned if all documents are returned in the initial batch
operations:
- name: createFindCursor
object: *collection0
arguments:
filter: {}
saveResultAsEntity: &cursor0 cursor0
- &assertConnectionNotPinned
name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 0
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
find: *collection0Name
filter: {}
commandName: find
- commandSucceededEvent:
reply:
cursor:
id: 0
firstBatch: { $$type: array }
ns: { $$type: string }
commandName: find
- client: *client0
eventType: cmap
events:
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
- description: pinned connections are returned when the cursor is drained
operations:
- &createAndSaveCursor
name: createFindCursor
object: *collection0
arguments:
filter: {}
batchSize: 2
saveResultAsEntity: &cursor0 cursor0
- &assertConnectionPinned
name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 1
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult: { _id: 1 }
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult: { _id: 2 }
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult: { _id: 3 }
- *assertConnectionNotPinned
- &closeCursor
name: close
object: *cursor0
expectEvents:
- client: *client0
events:
- &findWithBatchSizeStarted
commandStartedEvent:
command:
find: *collection0Name
filter: {}
batchSize: 2
commandName: find
- &findWithBatchSizeSucceeded
commandSucceededEvent:
reply:
cursor:
id: { $$type: long }
firstBatch: { $$type: array }
ns: { $$type: string }
commandName: find
- &getMoreStarted
commandStartedEvent:
command:
getMore: { $$type: long }
collection: *collection0Name
commandName: getMore
- &getMoreSucceeded
commandSucceededEvent:
reply:
cursor:
id: 0
ns: { $$type: string }
nextBatch: { $$type: array }
commandName: getMore
- client: *client0
eventType: cmap
events:
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
- description: pinned connections are returned to the pool when the cursor is closed
operations:
- *createAndSaveCursor
- *assertConnectionPinned
- *closeCursor
- *assertConnectionNotPinned
expectEvents:
- client: *client0
events:
- *findWithBatchSizeStarted
- *findWithBatchSizeSucceeded
- &killCursorsStarted
commandStartedEvent:
commandName: killCursors
- &killCursorsSucceeded
commandSucceededEvent:
commandName: killCursors
- client: *client0
eventType: cmap
events:
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# If a network error occurs during a getMore request, the connection must remain pinned. and drivers must not
# attempt to send a killCursors command when the cursor is closed because the connection is no longer valid.
- description: pinned connections are not returned after an network error during getMore
operations:
- name: failPoint
object: testRunner
arguments:
client: *client0
failPoint:
configureFailPoint: failCommand
mode: { times: 1 }
data:
failCommands: [ getMore ]
closeConnection: true
- *createAndSaveCursor
- *assertConnectionPinned
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult:
_id: 1
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult:
_id: 2
# Third next() call should perform a getMore.
- name: iterateUntilDocumentOrError
object: *cursor0
expectError:
# Network errors are considered client-side errors per the unified test format spec.
isClientError: true
- *assertConnectionPinned
- *closeCursor # Execute a close operation to actually release the connection.
- *assertConnectionNotPinned
expectEvents:
- client: *client0
events:
- *findWithBatchSizeStarted
- *findWithBatchSizeSucceeded
- *getMoreStarted
- &getMoreFailed
commandFailedEvent:
commandName: getMore
- client: *client0
eventType: cmap
events:
# Events to set the failpoint.
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# Events for the find command + getMore.
- connectionCheckedOutEvent: {}
# Events for the close() operation.
- connectionCheckedInEvent: {}
- connectionClosedEvent:
reason: error
- description: pinned connections are returned after a network error during a killCursors request
operations:
- name: failPoint
object: testRunner
arguments:
client: *client0
failPoint:
configureFailPoint: failCommand
mode: { times: 1 }
data:
failCommands: [ killCursors ]
closeConnection: true
- *createAndSaveCursor
- *assertConnectionPinned
- *closeCursor
- *assertConnectionNotPinned
expectEvents:
- client: *client0
events:
- *findWithBatchSizeStarted
- *findWithBatchSizeSucceeded
- *killCursorsStarted
- commandFailedEvent:
commandName: killCursors
- client: *client0
eventType: cmap
events:
# Events to set the failpoint.
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# Events for the find command + killCursors.
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
- connectionClosedEvent:
reason: error
- description: pinned connections are not returned to the pool after a non-network error on getMore
operations:
- name: failPoint
object: testRunner
arguments:
client: *client0
failPoint:
configureFailPoint: failCommand
mode: { times: 1 }
data:
failCommands: [ getMore ]
errorCode: &hostNotFoundCode 7 # This is not a state change error code, so it should not cause SDAM changes.
- *createAndSaveCursor
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult:
_id: 1
- name: iterateUntilDocumentOrError
object: *cursor0
expectResult:
_id: 2
- name: iterateUntilDocumentOrError
object: *cursor0
expectError:
errorCode: *hostNotFoundCode
- *assertConnectionPinned
- *closeCursor
- *assertConnectionNotPinned
expectEvents:
- client: *client0
events:
- *findWithBatchSizeStarted
- *findWithBatchSizeSucceeded
- *getMoreStarted
- *getMoreFailed
- *killCursorsStarted
- *killCursorsSucceeded
- client: *client0
eventType: cmap
events:
# Events to set the failpoint.
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# Events for the find command + getMore + killCursors.
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# Basic tests for cursor-creating commands besides "find". We don't need to replicate the full set of tests defined
# above for each such command. Instead, only one test is needed per command to ensure that the pinned connection is
# correctly passed down to the server.
#
# Each test creates a cursor with a small batch size and fully iterates it. Because drivers do not publish CMAP
# events when using pinned connections, each test asserts that only one set of ready/checkout/checkin events are
# published.
- description: aggregate pins the cursor to a connection
operations:
- name: aggregate
object: *collection0
arguments:
pipeline: []
batchSize: 2
- name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 0
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
aggregate: *collection0Name
cursor:
batchSize: 2
commandName: aggregate
- commandSucceededEvent:
commandName: aggregate
- *getMoreStarted
- *getMoreSucceeded
- client: *client0
eventType: cmap
events:
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
- description: listCollections pins the cursor to a connection
runOnRequirements:
- serverless: forbid # CLOUDP-98562 listCollections batchSize is ignored on serverless.
operations:
- name: listCollections
object: *database0
arguments:
filter: {}
batchSize: 2
- name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 0
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
listCollections: 1
cursor:
batchSize: 2
commandName: listCollections
databaseName: *database0Name
- commandSucceededEvent:
commandName: listCollections
# Write out the event for getMore rather than using the getMoreStarted anchor because the "collection" field
# is not equal to *collection0Name as the command is not executed against a collection.
- commandStartedEvent:
command:
getMore: { $$type: long }
collection: { $$type: string }
commandName: getMore
- *getMoreSucceeded
- client: *client0
eventType: cmap
events:
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
- description: listIndexes pins the cursor to a connection
operations:
# There is an automatic index on _id so we create two more indexes to force multiple batches with batchSize=2.
- name: createIndex
object: *collection0
arguments:
keys: &x1IndexSpec { x: 1 }
name: &x1IndexName x_1
- name: createIndex
object: *collection0
arguments:
keys: &y1IndexSpec { y: 1 }
name: &y1IndexName y_1
- name: listIndexes
object: *collection0
arguments:
batchSize: 2
- name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 0
expectEvents:
- client: *client0
events:
- commandStartedEvent:
command:
createIndexes: *collection0Name
indexes:
- name: *x1IndexName
key: *x1IndexSpec
commandName: createIndexes
- commandSucceededEvent:
commandName: createIndexes
- commandStartedEvent:
command:
createIndexes: *collection0Name
indexes:
- name: *y1IndexName
key: *y1IndexSpec
commandName: createIndexes
- commandSucceededEvent:
commandName: createIndexes
- commandStartedEvent:
command:
listIndexes: *collection0Name
cursor:
batchSize: 2
commandName: listIndexes
databaseName: *database0Name
- commandSucceededEvent:
commandName: listIndexes
- *getMoreStarted
- *getMoreSucceeded
- client: *client0
eventType: cmap
events:
# Events for first createIndexes.
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# Events for second createIndexes.
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
# Events for listIndexes and getMore.
- connectionCheckedOutEvent: {}
- connectionCheckedInEvent: {}
- description: change streams pin to a connection
runOnRequirements:
- serverless: forbid # Serverless does not support change streams.
operations:
- name: createChangeStream
object: *collection0
arguments:
pipeline: []
saveResultAsEntity: &changeStream0 changeStream0
- name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 1
- name: close
object: *changeStream0
- name: assertNumberConnectionsCheckedOut
object: testRunner
arguments:
client: *client0
connections: 0
expectEvents:
- client: *client0
events:
- commandStartedEvent:
commandName: aggregate
- commandSucceededEvent:
commandName: aggregate
- commandStartedEvent:
commandName: killCursors
- commandSucceededEvent:
commandName: killCursors
- client: *client0
eventType: cmap
events:
# Events for creating the change stream.
- connectionReadyEvent: {}
- connectionCheckedOutEvent: {}
# Events for closing the change stream.
- connectionCheckedInEvent: {}