diff --git a/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst b/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst index 0a3d8997a4..0a1ab09974 100644 --- a/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst +++ b/source/connection-monitoring-and-pooling/connection-monitoring-and-pooling.rst @@ -452,6 +452,11 @@ Before a `Connection <#connection>`_ can be marked as either "available" or "in must be established. This process involves performing the initial handshake, handling OP_COMPRESSED, and performing authentication. +If an error is encountered while attempting to establish a connection, it MUST be handled according +to the `Application Errors`_ section in the SDAM specification. After the SDAM machinery has handled the error, +the connection MUST be `closed <#closing-a-connection-internal-implementation>`_. The error can then be propagated +to the context that initiated the connection establishment attempt. + .. code:: try: @@ -462,8 +467,11 @@ handshake, handling OP_COMPRESSED, and performing authentication. emit ConnectionReadyEvent and equivalent log message return connection except error: + # Handle error according to SDAM. This may entail clearing the pool. + topology.handle_pre_handshake_error(error) close connection - throw error # Propagate error in manner idiomatic to language. + # Propagate error in manner idiomatic to language. + throw error Closing a Connection (Internal Implementation) @@ -519,10 +527,6 @@ Populating the pool MUST NOT block any application threads. For example, it could be performed on a background thread or via the use of non-blocking/async I/O. Populating the pool MUST NOT be performed unless the pool is "ready". -If an error is encountered while populating a connection, it MUST be handled via -the SDAM machinery according to the `Application Errors`_ section in the SDAM -specification. - If minPoolSize is set, the `Connection <#connection>`_ Pool MUST be populated until it has at least minPoolSize total `Connections <#connection>`_. This MUST occur only while the pool is "ready". If the pool implements a background @@ -544,12 +548,9 @@ established as a result of populating the Pool. wait until pendingConnectionCount < maxConnecting and pool is "ready" create connection - try: - establish connection - mark connection as available - except error: - # Defer error handling to SDAM. - topology.handle_pre_handshake_error(error) + try establish connection + mark connection as available + decrement pendingConnectionCount Checking Out a Connection ------------------------- @@ -573,17 +574,26 @@ available `Connection`_ is found or the list of available `Connections If the list is exhausted, the total number of `Connections <#connection>`_ is less than maxPoolSize, and pendingConnectionCount < maxConnecting, the pool MUST -create a `Connection`_, establish it, mark it as "in use" and return it. If -totalConnectionCount == maxPoolSize or pendingConnectionCount == maxConnecting, -then the pool MUST wait to service the request until neither of those two -conditions are met or until a `Connection`_ becomes available, re-entering the -checkOut loop in either case. This waiting MUST NOT prevent `Connections -<#connection>`_ from being checked into the pool. Additionally, the Pool MUST -NOT service any newer checkOut requests before fulfilling the original one which -could not be fulfilled. For drivers that implement the WaitQueue via a fair -semaphore, a condition variable may also be needed to to meet this -requirement. Waiting on the condition variable SHOULD also be limited by the -WaitQueueTimeout, if the driver supports one and it was specified by the user. +create a `Connection`_ (as described in `Creating a Connection +<#creating-a-connection-internal-implementation>`_), establish it (as described +in `Establishing a Connection +<#establishing-a-connection-internal-implementation>`_), mark it as "in use" and +return it. If an error is encountered while attempting to establish the +connection, the pool MUST emit a ConnectionCheckOutFailed event with reason +"connectionError" and a corresponding log message before propagating the error +to connection requester. + +If the list is exhausted and totalConnectionCount == maxPoolSize or +pendingConnectionCount == maxConnecting, then the pool MUST wait to service the +request until neither of those two conditions are met or until a `Connection`_ +becomes available, re-entering the checkOut loop in either case. This waiting +MUST NOT prevent `Connections <#connection>`_ from being checked into the +pool. Additionally, the Pool MUST NOT service any newer checkOut requests before +fulfilling the original one which could not be fulfilled. For drivers that +implement the WaitQueue via a fair semaphore, a condition variable may also be +needed to to meet this requirement. Waiting on the condition variable SHOULD +also be limited by the WaitQueueTimeout, if the driver supports one and it was +specified by the user. If the pool is "closed" or "paused", any attempt to check out a `Connection <#connection>`_ MUST throw an Error. The error thrown as a result of the pool @@ -654,15 +664,14 @@ Before a given `Connection <#connection>`_ is returned from checkOut, it must be if connection state is "pending": try: establish connection + set connection state to "in use" + decrement pendingConnectionCount except connection establishment error: emit ConnectionCheckOutFailedEvent(reason="connectionError") and equivalent log message - decrement totalConnectionCount throw - finally: - decrement pendingConnectionCount else: + set connection state to "in use" decrement availableConnectionCount - set connection state to "in use" emit ConnectionCheckedOutEvent and equivalent log message return connection @@ -683,6 +692,10 @@ true: Otherwise, the `Connection <#connection>`_ is marked as available. +If an error is encountered while reading from or writing to a checked out `Connection <#connection>`_, the error MUST +be handled according to the `Application Errors`_ section of the SDAM specification *before* the connection is checked +back into the pool. + .. code:: emit ConnectionCheckedInEvent and equivalent log message @@ -1549,6 +1562,7 @@ Changelog :2022-10-05: Remove spec front matter and reformat changelog. :2022-10-14: Add connection pool log messages and associated tests. :2023-04-17: Fix duplicate logging test description. +:2023-06-15: Clarify error handling semantics and add associated tests. ---- diff --git a/source/connection-monitoring-and-pooling/tests/README.rst b/source/connection-monitoring-and-pooling/tests/README.rst index ab7d8fac5c..e9c71630d5 100644 --- a/source/connection-monitoring-and-pooling/tests/README.rst +++ b/source/connection-monitoring-and-pooling/tests/README.rst @@ -14,8 +14,8 @@ Introduction Drivers MUST implement all of the following types of CMAP tests: * Pool unit and integration tests as described in `cmap-format/README.rst <./cmap-format/README.rst>`__ +* Integration tests written in the `Unified Test Format <../../unified-test-format/unified-test-format.rst>`_ located in the `/unified <./unified>`_ directory * Pool prose tests as described below in `Prose Tests`_ -* Logging tests as described below in `Logging Tests`_ Prose Tests =========== @@ -26,11 +26,4 @@ The following tests have not yet been automated, but MUST still be tested: #. All ConnectionPoolOptions MUST be the same for all pools created by a MongoClient #. A user MUST be able to specify all ConnectionPoolOptions via a URI string #. A user MUST be able to subscribe to Connection Monitoring Events in a manner idiomatic to their language and driver -#. When a check out attempt fails because connection set up throws an error, - assert that a ConnectionCheckOutFailedEvent with reason="connectionError" is emitted. -Logging Tests -============= - -Tests for connection pool logging can be found in the `/logging <./logging>`__ subdirectory and are written in the -`Unified Test Format <../../unified-test-format/unified-test-format.rst>`__. diff --git a/source/connection-monitoring-and-pooling/tests/cmap-format/README.rst b/source/connection-monitoring-and-pooling/tests/cmap-format/README.rst index 5bb72dd0fe..734f80f094 100644 --- a/source/connection-monitoring-and-pooling/tests/cmap-format/README.rst +++ b/source/connection-monitoring-and-pooling/tests/cmap-format/README.rst @@ -54,7 +54,14 @@ All Unit Tests have some of the following fields: - ``error``: Indicates that the main thread is expected to error during this test. An error may include of the following fields: - - ``type``: the type of error emitted + - ``type``: the type of error emitted. Currently, only the following error types are supported: + + - WaitQueueTimeoutError + - PoolClosedError + - PoolClearedError + - AuthenticationError + - NetworkError + - ``message``: the message associated with that error - ``address``: Address of pool emitting error @@ -126,6 +133,10 @@ the addition of the following fields to each test: it should be assumed that there is no upper bound on the required server version. + - ``auth`` (optional): If true, the tests MUST only run if authentication + is enabled. If false, tests MUST only run if authentication is not enabled. + If this field is omitted, there is no authentication requirement. + - ``failPoint``: optional, a document containing a ``configureFailPoint`` command to run against the endpoint being used for the test. diff --git a/source/connection-monitoring-and-pooling/tests/cmap-format/pool-checkout-error-checkin.json b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-checkout-error-checkin.json new file mode 100644 index 0000000000..51a9cc18b1 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-checkout-error-checkin.json @@ -0,0 +1,97 @@ +{ + "version": 1, + "style": "integration", + "description": "checking in a connection after checkout fails closes connection", + "runOn": [ + { + "minServerVersion": "4.9.0", + "auth": true + } + ], + "poolOptions": { + "appName": "poolCheckOutErrorCheckInTest" + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "skip": 1 + }, + "data": { + "failCommands": [ + "saslContinue" + ], + "closeConnection": true, + "appName": "poolCheckOutErrorCheckInTest" + } + }, + "operations": [ + { + "name": "ready" + }, + { + "name": "checkOut", + "label": "conn" + }, + { + "name": "start", + "target": "thread1" + }, + { + "name": "checkOut", + "thread": "thread1" + }, + { + "name": "waitForEvent", + "event": "ConnectionCheckOutFailed", + "count": 1 + }, + { + "name": "checkIn", + "connection": "conn" + } + ], + "events": [ + { + "type": "ConnectionCheckOutStarted" + }, + { + "type": "ConnectionCreated" + }, + { + "type": "ConnectionReady" + }, + { + "type": "ConnectionCheckedOut" + }, + { + "type": "ConnectionCheckOutStarted" + }, + { + "type": "ConnectionCreated" + }, + { + "type": "ConnectionPoolCleared" + }, + { + "type": "ConnectionClosed", + "reason": "error", + "connectionId": 2 + }, + { + "type": "ConnectionCheckOutFailed", + "reason": "connectionError" + }, + { + "type": "ConnectionCheckedIn" + }, + { + "type": "ConnectionClosed", + "connectionId": 1, + "reason": "stale" + } + ], + "ignore": [ + "ConnectionPoolCreated", + "ConnectionPoolReady" + ] +} diff --git a/source/connection-monitoring-and-pooling/tests/cmap-format/pool-checkout-error-checkin.yml b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-checkout-error-checkin.yml new file mode 100644 index 0000000000..28bea02730 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-checkout-error-checkin.yml @@ -0,0 +1,55 @@ +version: 1 +style: integration +description: checking in a connection after checkout fails closes connection +runOn: + - + # Required for appName in fail point + minServerVersion: "4.9.0" + auth: true +poolOptions: + appName: &appName "poolCheckOutErrorCheckInTest" +failPoint: + configureFailPoint: failCommand + # Skip the first so that the first checkOut succeeds. + mode: { skip: 1 } + data: + # Use saslContinue so that monitor checks won't interfere with this failpoint. + failCommands: ["saslContinue"] + closeConnection: true + appName: *appName +operations: + - name: ready + - name: checkOut + label: conn + # Perform check out in another thread so the main thread can continue to + # execute operations. + - name: start + target: thread1 + - name: checkOut + thread: thread1 + # Wait for the check out to fail + - name: waitForEvent + event: ConnectionCheckOutFailed + count: 1 + - name: checkIn + connection: conn +events: + - type: ConnectionCheckOutStarted + - type: ConnectionCreated + - type: ConnectionReady + - type: ConnectionCheckedOut + - type: ConnectionCheckOutStarted + - type: ConnectionCreated + - type: ConnectionPoolCleared + - type: ConnectionClosed + reason: error + connectionId: 2 + - type: ConnectionCheckOutFailed + reason: connectionError + - type: ConnectionCheckedIn + - type: ConnectionClosed + connectionId: 1 + reason: stale +ignore: + - ConnectionPoolCreated + - ConnectionPoolReady diff --git a/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.json b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.json index 1c744b850c..509b2a2356 100644 --- a/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.json +++ b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.json @@ -49,15 +49,15 @@ "type": "ConnectionCreated", "address": 42 }, + { + "type": "ConnectionPoolCleared", + "address": 42 + }, { "type": "ConnectionClosed", "address": 42, "connectionId": 42, "reason": "error" - }, - { - "type": "ConnectionPoolCleared", - "address": 42 } ], "ignore": [ diff --git a/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.yml b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.yml index dd5890b1d9..f43c4ee154 100644 --- a/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.yml +++ b/source/connection-monitoring-and-pooling/tests/cmap-format/pool-create-min-size-error.yml @@ -30,11 +30,11 @@ events: address: 42 - type: ConnectionCreated address: 42 + - type: ConnectionPoolCleared + address: 42 - type: ConnectionClosed address: 42 connectionId: 42 reason: error - - type: ConnectionPoolCleared - address: 42 ignore: - ConnectionPoolCreated diff --git a/source/connection-monitoring-and-pooling/tests/unified/auth-error.json b/source/connection-monitoring-and-pooling/tests/unified/auth-error.json new file mode 100644 index 0000000000..6704a54627 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/auth-error.json @@ -0,0 +1,172 @@ +{ + "description": "cmap-auth-error", + "schemaVersion": "1.10", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "serverless": "forbid", + "topologies": [ + "single", + "replicaset", + "sharded" + ], + "auth": true + } + ], + "createEntities": [ + { + "client": { + "id": "setupClient", + "useMultipleMongoses": false + } + } + ], + "initialData": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "Pool is cleared after auth error during checkout", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "setupClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "saslContinue" + ], + "errorCode": 18, + "appName": "cmapAuthErrorTest" + } + } + } + }, + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "connectionCheckOutStartedEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "connectionClosedEvent", + "poolClearedEvent", + "connectionReadyEvent", + "connectionCreatedEvent" + ], + "uriOptions": { + "retryWrites": false, + "retryReads": false, + "appname": "cmapAuthErrorTest" + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "cmap-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "cmap-network-error" + } + } + ] + } + }, + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "connectionCheckOutFailedEvent": {} + }, + "count": 1 + } + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "cmap", + "events": [ + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCreatedEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/source/connection-monitoring-and-pooling/tests/unified/auth-error.yml b/source/connection-monitoring-and-pooling/tests/unified/auth-error.yml new file mode 100644 index 0000000000..ce6edaf7bc --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/auth-error.yml @@ -0,0 +1,100 @@ +--- +description: cmap-auth-error + +schemaVersion: "1.10" + +runOnRequirements: + # failCommand appName requirements + - minServerVersion: "4.4" + serverless: forbid + topologies: [ single, replicaset, sharded ] + auth: true + +createEntities: + - client: + id: &setupClient setupClient + useMultipleMongoses: false + +initialData: &initialData + - collectionName: &collectionName cmap-network-error + databaseName: &databaseName cmap-tests + documents: + - _id: 1 + - _id: 2 + +tests: + - description: Pool is cleared after auth error during checkout + operations: + - name: failPoint + object: testRunner + arguments: + client: *setupClient + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - saslContinue + errorCode: 18 + appName: &authErrorAppName cmapAuthErrorTest + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + useMultipleMongoses: false + observeEvents: + - connectionCheckOutStartedEvent + - connectionCheckedOutEvent + - connectionCheckOutFailedEvent + - connectionCheckedInEvent + - connectionClosedEvent + - poolClearedEvent + - connectionReadyEvent + - connectionCreatedEvent + uriOptions: + retryWrites: false + retryReads: false + appname: *authErrorAppName + - database: + id: &database database + client: *client + databaseName: *databaseName + - collection: + id: &collection collection + database: *database + collectionName: *collectionName + - name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + connectionCheckOutFailedEvent: {} + count: 1 + expectEvents: + - client: *client + eventType: cmap + events: + - connectionCheckOutStartedEvent: {} + - connectionCreatedEvent: {} + - poolClearedEvent: {} + - connectionClosedEvent: + reason: error + - connectionCheckOutFailedEvent: + reason: connectionError + + outcome: + - collectionName: *collectionName + databaseName: *databaseName + documents: + - _id: 1 + - _id: 2 diff --git a/source/connection-monitoring-and-pooling/tests/unified/checkout-error-clears-waitqueue.json b/source/connection-monitoring-and-pooling/tests/unified/checkout-error-clears-waitqueue.json new file mode 100644 index 0000000000..7a87fc8e57 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/checkout-error-clears-waitqueue.json @@ -0,0 +1,269 @@ +{ + "description": "checkout-error-clears-waitqueue", + "schemaVersion": "1.10", + "createEntities": [ + { + "client": { + "id": "setupClient", + "useMultipleMongoses": false + } + } + ], + "initialData": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "Connection error during checkout clears WaitQueue", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "serverless": "forbid", + "topologies": [ + "single", + "replicaset", + "sharded" + ] + } + ], + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "connectionCreatedEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "poolClearedEvent" + ], + "uriOptions": { + "retryWrites": false, + "retryReads": false, + "appname": "poolCheckOutErrorWaitQueueTest", + "serverSelectionTimeoutMS": 100, + "waitQueueTimeoutMS": 30000, + "directConnection": true, + "maxPoolSize": 1 + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "cmap-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "cmap-network-error" + } + }, + { + "thread": { + "id": "thread0" + } + }, + { + "thread": { + "id": "thread1" + } + }, + { + "thread": { + "id": "thread2" + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "poolReadyEvent": {} + }, + "count": 1 + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "setupClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 50 + }, + "data": { + "failCommands": [ + "hello", + "isMaster" + ], + "appName": "poolCheckOutErrorWaitQueueTest", + "closeConnection": true, + "blockConnection": true, + "blockTimeMS": 1000 + } + } + } + }, + { + "name": "runOnThread", + "object": "testRunner", + "arguments": { + "thread": "thread0", + "operation": { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + } + }, + { + "name": "runOnThread", + "object": "testRunner", + "arguments": { + "thread": "thread1", + "operation": { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + } + }, + { + "name": "runOnThread", + "object": "testRunner", + "arguments": { + "thread": "thread2", + "operation": { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + } + }, + { + "name": "waitForThread", + "object": "testRunner", + "arguments": { + "thread": "thread0" + } + }, + { + "name": "waitForThread", + "object": "testRunner", + "arguments": { + "thread": "thread1" + } + }, + { + "name": "waitForThread", + "object": "testRunner", + "arguments": { + "thread": "thread2" + } + }, + { + "name": "assertEventCount", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "connectionClosedEvent": {} + }, + "count": 1 + } + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "cmap", + "events": [ + { + "connectionCreatedEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/source/connection-monitoring-and-pooling/tests/unified/checkout-error-clears-waitqueue.yml b/source/connection-monitoring-and-pooling/tests/unified/checkout-error-clears-waitqueue.yml new file mode 100644 index 0000000000..c070cef4f3 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/checkout-error-clears-waitqueue.yml @@ -0,0 +1,162 @@ +--- +description: checkout-error-clears-waitqueue + +schemaVersion: "1.10" + +createEntities: + - client: + id: &setupClient setupClient + useMultipleMongoses: false + +initialData: &initialData + - collectionName: &collectionName cmap-network-error + databaseName: &databaseName cmap-tests + documents: + - _id: 1 + - _id: 2 + +tests: + - description: Connection error during checkout clears WaitQueue + runOnRequirements: + # failCommand appName requirements + - minServerVersion: "4.4" + serverless: forbid + topologies: [ single, replicaset, sharded ] + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + useMultipleMongoses: false + observeEvents: + - connectionCreatedEvent + - connectionCheckedOutEvent + - connectionCheckOutFailedEvent + - connectionCheckedInEvent + - poolClearedEvent + uriOptions: + retryWrites: false + retryReads: false + appname: &appName "poolCheckOutErrorWaitQueueTest" + serverSelectionTimeoutMS: 100 + waitQueueTimeoutMS: 30000 + directConnection: true + maxPoolSize: 1 + - database: + id: &database database + client: *client + databaseName: *databaseName + - collection: + id: &collection collection + database: *database + collectionName: *collectionName + - thread: + id: &thread0 thread0 + - thread: + id: &thread1 thread1 + - thread: + id: &thread2 thread2 + # wait for the server to be discovered before enabling the failpoint + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + poolReadyEvent: {} + count: 1 + - name: failPoint + object: testRunner + arguments: + client: *setupClient + failPoint: + configureFailPoint: failCommand + # high amount to ensure not interfered with by monitor checks. + mode: { times: 50 } + data: + failCommands: ["hello", "isMaster"] + appName: *appName + closeConnection: true + blockConnection: true + blockTimeMS: 1000 + # Start three concurrent checkOut attempts. + # Since maxPoolSize=1 and hello will block for a while, two of the threads will enter the WaitQueue. + # Once the checkOut finally fails, the pool will be cleared and the two other threads will be evicted from the + # WaitQueue without ever having attempted to create a connection. + - name: runOnThread + object: testRunner + arguments: + thread: *thread0 + operation: + name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: runOnThread + object: testRunner + arguments: + thread: *thread1 + operation: + name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: runOnThread + object: testRunner + arguments: + thread: *thread2 + operation: + name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: waitForThread + object: testRunner + arguments: + thread: *thread0 + - name: waitForThread + object: testRunner + arguments: + thread: *thread1 + - name: waitForThread + object: testRunner + arguments: + thread: *thread2 + - name: assertEventCount + object: testRunner + arguments: + client: *client + event: + connectionClosedEvent: {} + count: 1 + expectEvents: + - client: *client + eventType: cmap + events: + # Only one ConnectionCreatedEvent should be emitted, since the other threads should be evicted by + # the pool clear without ever attempting to create a connection. + - connectionCreatedEvent: {} + - poolClearedEvent: {} + - connectionCheckOutFailedEvent: + reason: connectionError + - connectionCheckOutFailedEvent: + reason: connectionError + - connectionCheckOutFailedEvent: + reason: connectionError + + outcome: + - collectionName: *collectionName + databaseName: *databaseName + documents: + - _id: 1 + - _id: 2 diff --git a/source/connection-monitoring-and-pooling/tests/unified/concurrent-checkout-error.json b/source/connection-monitoring-and-pooling/tests/unified/concurrent-checkout-error.json new file mode 100644 index 0000000000..e9a39dbc44 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/concurrent-checkout-error.json @@ -0,0 +1,250 @@ +{ + "description": "concurrent-checkout-error", + "schemaVersion": "1.10", + "createEntities": [ + { + "client": { + "id": "setupClient", + "useMultipleMongoses": false + } + } + ], + "initialData": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "Pool properly handles multiple concurrent network errors on check out", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "serverless": "forbid", + "topologies": [ + "single", + "replicaset", + "sharded" + ] + } + ], + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "poolReadyEvent", + "poolClearedEvent" + ], + "uriOptions": { + "retryWrites": false, + "retryReads": false, + "appname": "poolConcurrentCheckOutErrorTest", + "serverSelectionTimeoutMS": 100, + "waitQueueTimeoutMS": 30000, + "directConnection": true + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "cmap-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "cmap-network-error" + } + }, + { + "thread": { + "id": "thread0" + } + }, + { + "thread": { + "id": "thread1" + } + }, + { + "thread": { + "id": "thread2" + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "poolReadyEvent": {} + }, + "count": 1 + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "setupClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 50 + }, + "data": { + "failCommands": [ + "hello", + "isMaster" + ], + "appName": "poolConcurrentCheckOutErrorTest", + "closeConnection": true, + "blockConnection": true, + "blockTimeMS": 1000 + } + } + } + }, + { + "name": "runOnThread", + "object": "testRunner", + "arguments": { + "thread": "thread0", + "operation": { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + } + }, + { + "name": "runOnThread", + "object": "testRunner", + "arguments": { + "thread": "thread1", + "operation": { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + } + }, + { + "name": "runOnThread", + "object": "testRunner", + "arguments": { + "thread": "thread2", + "operation": { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + } + }, + { + "name": "waitForThread", + "object": "testRunner", + "arguments": { + "thread": "thread0" + } + }, + { + "name": "waitForThread", + "object": "testRunner", + "arguments": { + "thread": "thread1" + } + }, + { + "name": "waitForThread", + "object": "testRunner", + "arguments": { + "thread": "thread2" + } + }, + { + "name": "assertEventCount", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "poolClearedEvent": {} + }, + "count": 1 + } + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "cmap", + "events": [ + { + "poolReadyEvent": {} + }, + { + "poolClearedEvent": {} + } + ] + } + ], + "outcome": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/source/connection-monitoring-and-pooling/tests/unified/concurrent-checkout-error.yml b/source/connection-monitoring-and-pooling/tests/unified/concurrent-checkout-error.yml new file mode 100644 index 0000000000..7f37627682 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/concurrent-checkout-error.yml @@ -0,0 +1,149 @@ +--- +description: concurrent-checkout-error + +schemaVersion: "1.10" + +createEntities: + - client: + id: &setupClient setupClient + useMultipleMongoses: false + +initialData: &initialData + - collectionName: &collectionName cmap-network-error + databaseName: &databaseName cmap-tests + documents: + - _id: 1 + - _id: 2 + +tests: + - description: Pool properly handles multiple concurrent network errors on check out + runOnRequirements: + # failCommand appName requirements + - minServerVersion: "4.4" + serverless: forbid + topologies: [ single, replicaset, sharded ] + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + useMultipleMongoses: false + observeEvents: + - poolReadyEvent + - poolClearedEvent + uriOptions: + retryWrites: false + retryReads: false + appname: &appName "poolConcurrentCheckOutErrorTest" + serverSelectionTimeoutMS: 100 + waitQueueTimeoutMS: 30000 + directConnection: true + - database: + id: &database database + client: *client + databaseName: *databaseName + - collection: + id: &collection collection + database: *database + collectionName: *collectionName + - thread: + id: &thread0 thread0 + - thread: + id: &thread1 thread1 + - thread: + id: &thread2 thread2 + # wait for the server to be discovered before enabling the failpoint + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + poolReadyEvent: {} + count: 1 + - name: failPoint + object: testRunner + arguments: + client: *setupClient + failPoint: + configureFailPoint: failCommand + # high amount to ensure not interfered with by monitor checks. + mode: { times: 50 } + data: + failCommands: ["hello", "isMaster"] + appName: *appName + closeConnection: true + blockConnection: true + blockTimeMS: 1000 + # Start three concurrent checkOut attempts. The failpoint blocks for 1s before closing the connection, so all + # three checkOuts should receive network errors. + - name: runOnThread + object: testRunner + arguments: + thread: *thread0 + operation: + name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: runOnThread + object: testRunner + arguments: + thread: *thread1 + operation: + name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: runOnThread + object: testRunner + arguments: + thread: *thread2 + operation: + name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: waitForThread + object: testRunner + arguments: + thread: *thread0 + - name: waitForThread + object: testRunner + arguments: + thread: *thread1 + - name: waitForThread + object: testRunner + arguments: + thread: *thread2 + - name: assertEventCount + object: testRunner + arguments: + client: *client + event: + poolClearedEvent: {} + count: 1 + expectEvents: + - client: *client + eventType: cmap + events: + # The pool should only be cleared once despite the multiple errors. + - poolReadyEvent: {} + - poolClearedEvent: {} + + outcome: + - collectionName: *collectionName + databaseName: *databaseName + documents: + - _id: 1 + - _id: 2 diff --git a/source/connection-monitoring-and-pooling/tests/logging/connection-logging.json b/source/connection-monitoring-and-pooling/tests/unified/connection-logging.json similarity index 100% rename from source/connection-monitoring-and-pooling/tests/logging/connection-logging.json rename to source/connection-monitoring-and-pooling/tests/unified/connection-logging.json diff --git a/source/connection-monitoring-and-pooling/tests/logging/connection-logging.yml b/source/connection-monitoring-and-pooling/tests/unified/connection-logging.yml similarity index 100% rename from source/connection-monitoring-and-pooling/tests/logging/connection-logging.yml rename to source/connection-monitoring-and-pooling/tests/unified/connection-logging.yml diff --git a/source/connection-monitoring-and-pooling/tests/logging/connection-pool-options.json b/source/connection-monitoring-and-pooling/tests/unified/connection-pool-options-logging.json similarity index 100% rename from source/connection-monitoring-and-pooling/tests/logging/connection-pool-options.json rename to source/connection-monitoring-and-pooling/tests/unified/connection-pool-options-logging.json diff --git a/source/connection-monitoring-and-pooling/tests/logging/connection-pool-options.yml b/source/connection-monitoring-and-pooling/tests/unified/connection-pool-options-logging.yml similarity index 100% rename from source/connection-monitoring-and-pooling/tests/logging/connection-pool-options.yml rename to source/connection-monitoring-and-pooling/tests/unified/connection-pool-options-logging.yml diff --git a/source/connection-monitoring-and-pooling/tests/unified/network-error.json b/source/connection-monitoring-and-pooling/tests/unified/network-error.json new file mode 100644 index 0000000000..2db0396e25 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/network-error.json @@ -0,0 +1,469 @@ +{ + "description": "cmap-network-error", + "schemaVersion": "1.10", + "createEntities": [ + { + "client": { + "id": "setupClient", + "useMultipleMongoses": false + } + } + ], + "initialData": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "Pool properly handles network error on checked out connection", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "serverless": "forbid", + "topologies": [ + "single", + "replicaset", + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "setupClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "closeConnection": true, + "appName": "cmapNetworkErrorTest" + } + } + } + }, + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "connectionCheckOutStartedEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "connectionClosedEvent", + "poolClearedEvent" + ], + "uriOptions": { + "retryWrites": false, + "retryReads": false, + "appname": "cmapNetworkErrorTest" + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "cmap-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "cmap-network-error" + } + } + ] + } + }, + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "connectionClosedEvent": {} + }, + "count": 1 + } + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "cmap", + "events": [ + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "Pool properly handles network error during checkout", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "serverless": "forbid", + "topologies": [ + "single", + "sharded" + ] + } + ], + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "connectionCheckOutStartedEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "connectionClosedEvent", + "poolClearedEvent", + "connectionCreatedEvent", + "connectionReadyEvent", + "poolReadyEvent" + ], + "uriOptions": { + "retryWrites": false, + "retryReads": false, + "appName": "cmapNetworkErrorCheckOutTest", + "heartbeatFrequencyMS": 30000 + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "cmap-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "cmap-network-error" + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "poolReadyEvent": {} + }, + "count": 1 + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "setupClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "isMaster", + "hello" + ], + "closeConnection": true, + "appName": "cmapNetworkErrorCheckOutTest" + } + } + } + }, + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "connectionCheckOutFailedEvent": {} + }, + "count": 1 + } + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "cmap", + "events": [ + { + "poolReadyEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCreatedEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "cmap-network-error", + "databaseName": "cmap-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "Pool properly handles network error during minPoolSize background connection creation", + "runOnRequirements": [ + { + "minServerVersion": "4.4", + "serverless": "forbid", + "topologies": [ + "single", + "sharded" + ], + "auth": true + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "setupClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "saslContinue" + ], + "appName": "CMAPminPoolSizeError", + "closeConnection": true + } + } + } + }, + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client", + "useMultipleMongoses": false, + "observeEvents": [ + "poolClearedEvent", + "poolReadyEvent", + "connectionCreatedEvent", + "connectionReadyEvent", + "connectionClosedEvent", + "connectionCheckOutStartedEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent" + ], + "uriOptions": { + "heartbeatFrequencyMS": 500, + "appname": "CMAPminPoolSizeError", + "minPoolSize": 1 + } + } + } + ] + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "poolReadyEvent": {} + }, + "count": 1 + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "connectionClosedEvent": { + "reason": "error" + } + }, + "count": 1 + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "poolReadyEvent": {} + }, + "count": 2 + } + }, + { + "name": "waitForEvent", + "object": "testRunner", + "arguments": { + "client": "client", + "event": { + "connectionReadyEvent": {} + }, + "count": 1 + } + } + ], + "expectEvents": [ + { + "client": "client", + "eventType": "cmap", + "events": [ + { + "poolReadyEvent": {} + }, + { + "connectionCreatedEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "poolReadyEvent": {} + }, + { + "connectionCreatedEvent": {} + }, + { + "connectionReadyEvent": {} + } + ] + } + ] + } + ] +} diff --git a/source/connection-monitoring-and-pooling/tests/unified/network-error.yml b/source/connection-monitoring-and-pooling/tests/unified/network-error.yml new file mode 100644 index 0000000000..3a42ecbfd4 --- /dev/null +++ b/source/connection-monitoring-and-pooling/tests/unified/network-error.yml @@ -0,0 +1,287 @@ +--- +description: cmap-network-error + +schemaVersion: "1.10" + +createEntities: + - client: + id: &setupClient setupClient + useMultipleMongoses: false + +initialData: &initialData + - collectionName: &collectionName cmap-network-error + databaseName: &databaseName cmap-tests + documents: + - _id: 1 + - _id: 2 + +tests: + - description: Pool properly handles network error on checked out connection + runOnRequirements: + # failCommand appName requirements + - minServerVersion: "4.4" + serverless: forbid + topologies: [ single, replicaset, sharded ] + operations: + - name: failPoint + object: testRunner + arguments: + client: *setupClient + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - find + closeConnection: true + appName: &appName cmapNetworkErrorTest + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + useMultipleMongoses: false + observeEvents: + - connectionCheckOutStartedEvent + - connectionCheckedOutEvent + - connectionCheckOutFailedEvent + - connectionCheckedInEvent + - connectionClosedEvent + - poolClearedEvent + uriOptions: + retryWrites: false + retryReads: false + appname: *appName + - database: + id: &database database + client: *client + databaseName: *databaseName + - collection: + id: &collection collection + database: *database + collectionName: *collectionName + - name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + connectionClosedEvent: {} + count: 1 + expectEvents: + - client: *client + eventType: cmap + events: + - connectionCheckOutStartedEvent: {} + - connectionCheckedOutEvent: {} + # SDAM error handling needs to be performed before the connection is checked into the pool. + - poolClearedEvent: {} + - connectionCheckedInEvent: {} + - connectionClosedEvent: + # Even though the connection is also stale, the reason it is being closed + # is due to an error. + reason: error + + outcome: + - collectionName: *collectionName + databaseName: *databaseName + documents: + - _id: 1 + - _id: 2 + + - description: Pool properly handles network error during checkout + runOnRequirements: + # failCommand appName requirements + - minServerVersion: "4.4" + serverless: forbid + topologies: [ single, sharded ] + operations: + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + useMultipleMongoses: false + observeEvents: + - connectionCheckOutStartedEvent + - connectionCheckedOutEvent + - connectionCheckOutFailedEvent + - connectionCheckedInEvent + - connectionClosedEvent + - poolClearedEvent + - connectionCreatedEvent + - connectionReadyEvent + - poolReadyEvent + uriOptions: + retryWrites: false + retryReads: false + appName: &networkErrorCheckOutAppName cmapNetworkErrorCheckOutTest + # Use a high frequency so that server does not get marked unknown before the find + # can be executed. + heartbeatFrequencyMS: 30000 + - database: + id: &database database + client: *client + databaseName: *databaseName + - collection: + id: &collection collection + database: *database + collectionName: *collectionName + # wait for the server to be discovered before enabling the failpoint + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + poolReadyEvent: {} + count: 1 + - name: failPoint + object: testRunner + arguments: + client: *setupClient + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - isMaster + - hello + closeConnection: true + appName: *networkErrorCheckOutAppName + - name: find + object: *collection + arguments: + filter: + _id: 1 + expectError: + isError: true + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + connectionCheckOutFailedEvent: {} + count: 1 + expectEvents: + - client: *client + eventType: cmap + events: + - poolReadyEvent: {} + - connectionCheckOutStartedEvent: {} + - connectionCreatedEvent: {} + # SDAM needs to handle the error before the pool proceeds with cleaning up the connection. + - poolClearedEvent: {} + - connectionClosedEvent: + reason: error + - connectionCheckOutFailedEvent: + reason: connectionError + + outcome: + - collectionName: *collectionName + databaseName: *databaseName + documents: + - _id: 1 + - _id: 2 + + - description: Pool properly handles network error during minPoolSize background connection creation + runOnRequirements: + # failCommand appName requirements + - minServerVersion: "4.4" + serverless: forbid + topologies: [ single, sharded ] + auth: true + operations: + # Configure the initial monitor handshake to succeed but the + # first background minPoolSize establishment to fail. + - name: failPoint + object: testRunner + arguments: + client: *setupClient + failPoint: + configureFailPoint: failCommand + mode: + times: 1 + data: + failCommands: + - saslContinue + appName: &minPoolSizeAppName CMAPminPoolSizeError + closeConnection: true + - name: createEntities + object: testRunner + arguments: + entities: + - client: + id: &client client + useMultipleMongoses: false + observeEvents: + - poolClearedEvent + - poolReadyEvent + - connectionCreatedEvent + - connectionReadyEvent + - connectionClosedEvent + - connectionCheckOutStartedEvent + - connectionCheckedOutEvent + - connectionCheckOutFailedEvent + - connectionCheckedInEvent + uriOptions: + heartbeatFrequencyMS: 500 + appname: *minPoolSizeAppName + minPoolSize: 1 + # Wait for monitor to succeed handshake and mark the pool as ready. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + poolReadyEvent: {} + count: 1 + # Background connection establishment due to minPoolSize should fail, + # causing the connection to close. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + connectionClosedEvent: + reason: error + count: 1 + # Wait for monitor to rediscover server and mark pool as ready again. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + poolReadyEvent: {} + count: 2 + # Now that the failpoint has been disabled (was set to times: 1), background + # connection creation should succeed. + - name: waitForEvent + object: testRunner + arguments: + client: *client + event: + connectionReadyEvent: {} + count: 1 + + expectEvents: + - client: *client + eventType: cmap + events: + - poolReadyEvent: {} + - connectionCreatedEvent: {} + - poolClearedEvent: {} + - connectionClosedEvent: + reason: error + - poolReadyEvent: {} + - connectionCreatedEvent: {} + - connectionReadyEvent: {}