508 lines
16 KiB
YAML
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: {}
|