diff --git a/.evergreen/ci_matrix_constants.js b/.evergreen/ci_matrix_constants.js index 1b38ceabefb..b4cc9d43ccc 100644 --- a/.evergreen/ci_matrix_constants.js +++ b/.evergreen/ci_matrix_constants.js @@ -1,4 +1,4 @@ -const MONGODB_VERSIONS = ['latest', 'rapid', '8.0', '7.0', '6.0', '5.0', '4.4', '4.2']; +const MONGODB_VERSIONS = ['latest', 'rapid', '8.0', '7.0', '6.0', '5.0', '4.4']; const versions = [ { codeName: 'iron', versionNumber: '20.19.0' }, { codeName: 'jod', versionNumber: 22 }, diff --git a/.evergreen/config.yml b/.evergreen/config.yml index f48d61f0229..02a6bde0c00 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -1330,54 +1330,6 @@ tasks: - func: install dependencies - func: bootstrap mongo-orchestration - func: run tests - - name: test-4.2-server - tags: - - '4.2' - - server - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: server} - - {key: SSL, value: nossl} - - {key: AUTH, value: auth} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - - name: test-4.2-replica_set - tags: - - '4.2' - - replica_set - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: replica_set} - - {key: SSL, value: nossl} - - {key: AUTH, value: auth} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - - name: test-4.2-sharded_cluster - tags: - - '4.2' - - sharded_cluster - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: sharded_cluster} - - {key: SSL, value: nossl} - - {key: AUTH, value: auth} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - name: test-latest-server-v1-api tags: - latest @@ -1733,22 +1685,6 @@ tasks: - func: install dependencies - func: bootstrap mongo-orchestration - func: run tls tests - - name: test-tls-support-4.2 - tags: - - tls-support - - tls-support-4.2 - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: SSL, value: ssl} - - {key: TOPOLOGY, value: server} - - {key: AUTH, value: auth} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tls tests - name: aws-latest-auth-test-run-aws-auth-test-with-regular-aws-credentials commands: - command: expansions.update @@ -2535,60 +2471,6 @@ tasks: - func: install dependencies - func: bootstrap mongo-orchestration - func: run tests - - name: test-4.2-server-noauth - tags: - - '4.2' - - server - - noauth - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: server} - - {key: AUTH, value: noauth} - - {key: SSL, value: nossl} - - {key: NODE_LTS_VERSION, value: 20.19.0} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - - name: test-4.2-replica_set-noauth - tags: - - '4.2' - - replica_set - - noauth - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: replica_set} - - {key: AUTH, value: noauth} - - {key: SSL, value: nossl} - - {key: NODE_LTS_VERSION, value: 20.19.0} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - - name: test-4.2-sharded_cluster-noauth - tags: - - '4.2' - - sharded_cluster - - noauth - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: sharded_cluster} - - {key: AUTH, value: noauth} - - {key: SSL, value: nossl} - - {key: NODE_LTS_VERSION, value: 20.19.0} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - name: test-lambda-example tags: - latest @@ -2734,22 +2616,6 @@ tasks: - func: install dependencies - func: bootstrap mongo-orchestration - func: run tests - - name: test-4.2-csfle-mongocryptd - tags: - - '4.2' - - sharded_cluster - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: sharded_cluster} - - {key: AUTH, value: auth} - - {key: NODE_LTS_VERSION, value: '24'} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - name: test-latest-server-ssl tags: - latest @@ -3170,66 +3036,6 @@ tasks: - func: install dependencies - func: bootstrap mongo-orchestration - func: run tests - - name: test-4.2-server-ssl - tags: - - '4.2' - - server - - ssl - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: server} - - {key: AUTH, value: auth} - - {key: SSL, value: ssl} - - {key: NODE_LTS_VERSION, value: '24'} - - {key: CLIENT_ENCRYPTION, value: 'true'} - - {key: TEST_CSFLE, value: 'true'} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - - name: test-4.2-replica_set-ssl - tags: - - '4.2' - - replica_set - - ssl - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: replica_set} - - {key: AUTH, value: auth} - - {key: SSL, value: ssl} - - {key: NODE_LTS_VERSION, value: '24'} - - {key: CLIENT_ENCRYPTION, value: 'true'} - - {key: TEST_CSFLE, value: 'true'} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests - - name: test-4.2-sharded_cluster-ssl - tags: - - '4.2' - - sharded_cluster - - ssl - commands: - - command: expansions.update - type: setup - params: - updates: - - {key: VERSION, value: '4.2'} - - {key: TOPOLOGY, value: sharded_cluster} - - {key: AUTH, value: auth} - - {key: SSL, value: ssl} - - {key: NODE_LTS_VERSION, value: '24'} - - {key: CLIENT_ENCRYPTION, value: 'true'} - - {key: TEST_CSFLE, value: 'true'} - - func: install dependencies - - func: bootstrap mongo-orchestration - - func: run tests task_groups: - name: test_gcpkms_task_group setup_group_can_fail_task: true @@ -3537,9 +3343,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-x509-authentication - test-atlas-connectivity @@ -3562,7 +3365,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: rhel80-large-Node22 display_name: rhel8 Node22 run_on: rhel80-large @@ -3592,9 +3394,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-x509-authentication - test-atlas-connectivity @@ -3617,7 +3416,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: rhel80-large-Node24 display_name: rhel8 Node24 run_on: rhel80-large @@ -3647,9 +3445,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-x509-authentication - test-atlas-connectivity @@ -3672,7 +3467,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: rhel80-large-node-latest display_name: rhel8 Node Latest run_on: rhel80-large @@ -3702,9 +3496,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-x509-authentication - test-atlas-connectivity @@ -3726,7 +3517,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: windows-2022-latest-large-iron display_name: Windows Node20.19.0 run_on: windows-2022-latest-large @@ -3756,9 +3546,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-socks5 - test-socks5-tls @@ -3770,7 +3557,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: windows-2022-latest-large-Node22 display_name: Windows Node22 run_on: windows-2022-latest-large @@ -3800,9 +3586,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-socks5 - test-socks5-tls @@ -3814,7 +3597,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: windows-2022-latest-large-Node24 display_name: Windows Node24 run_on: windows-2022-latest-large @@ -3844,9 +3626,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-socks5 - test-socks5-tls @@ -3858,7 +3637,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: windows-2022-latest-large-node-latest display_name: Windows Node Latest run_on: windows-2022-latest-large @@ -3888,9 +3666,6 @@ buildvariants: - test-4.4-server - test-4.4-replica_set - test-4.4-sharded_cluster - - test-4.2-server - - test-4.2-replica_set - - test-4.2-sharded_cluster - test-latest-server-v1-api - test-socks5-tls - test-snappy-compression @@ -3901,7 +3676,6 @@ buildvariants: - test-tls-support-6.0 - test-tls-support-5.0 - test-tls-support-4.4 - - test-tls-support-4.2 - name: rhel8-node20.19.0-test-csfle-mongocryptd display_name: rhel 8 Node20.19.0 test mongocryptd run_on: rhel80-large @@ -3917,7 +3691,6 @@ buildvariants: - test-6.0-csfle-mongocryptd - test-5.0-csfle-mongocryptd - test-4.4-csfle-mongocryptd - - test-4.2-csfle-mongocryptd - name: rhel8-node24-test-csfle-mongocryptd display_name: rhel 8 Node24 test mongocryptd run_on: rhel80-large @@ -3933,7 +3706,6 @@ buildvariants: - test-6.0-csfle-mongocryptd - test-5.0-csfle-mongocryptd - test-4.4-csfle-mongocryptd - - test-4.2-csfle-mongocryptd - name: macos-14-arm64 display_name: MacOS 14 ARM Node24 run_on: macos-14-arm64 @@ -4040,9 +3812,6 @@ buildvariants: - test-4.4-server-noauth - test-4.4-replica_set-noauth - test-4.4-sharded_cluster-noauth - - test-4.2-server-noauth - - test-4.2-replica_set-noauth - - test-4.2-sharded_cluster-noauth - name: rhel8-test-lambda display_name: AWS Lambda handler tests run_on: rhel80-large diff --git a/.evergreen/generate_evergreen_tasks.js b/.evergreen/generate_evergreen_tasks.js index db577a148b0..c3655852572 100644 --- a/.evergreen/generate_evergreen_tasks.js +++ b/.evergreen/generate_evergreen_tasks.js @@ -424,7 +424,7 @@ for (const { // Running CSFLE tests with mongocryptd const MONGOCRYPTD_CSFLE_TASKS = MONGODB_VERSIONS.filter( mongoVersion => - ['latest', 'rapid'].includes(mongoVersion) || semver.gte(`${mongoVersion}.0`, '4.2.0') + ['latest', 'rapid'].includes(mongoVersion) || semver.gte(`${mongoVersion}.0`, '4.4.0') ).map(mongoVersion => { return { name: `test-${mongoVersion}-csfle-mongocryptd`, diff --git a/.evergreen/run-kerberos-tests.sh b/.evergreen/run-kerberos-tests.sh index ce01e8bf881..c7064c792eb 100644 --- a/.evergreen/run-kerberos-tests.sh +++ b/.evergreen/run-kerberos-tests.sh @@ -14,17 +14,17 @@ echo "Writing keytab" # DON'T PRINT KEYTAB TO STDOUT set +o verbose if [[ "$OSTYPE" == "darwin"* ]]; then - echo ${KEYTAB_BASE64_AES} | base64 -D >"$(pwd)/.evergreen/drivers.keytab" + echo ${KEYTAB_BASE64_BUILD} | base64 -D >"$(pwd)/.evergreen/drivers.keytab" else - echo ${KEYTAB_BASE64_AES} | base64 -d >"$(pwd)/.evergreen/drivers.keytab" + echo ${KEYTAB_BASE64_BUILD} | base64 -d >"$(pwd)/.evergreen/drivers.keytab" fi echo "Running kdestroy" kdestroy -A echo "Running kinit" -kinit -k -t "$(pwd)/.evergreen/drivers.keytab" -p ${PRINCIPAL} +kinit -k -t "$(pwd)/.evergreen/drivers.keytab" -p ${PRINCIPAL_BUILD} -USER=$(node -p "encodeURIComponent(process.env.PRINCIPAL)") -export MONGODB_URI="mongodb://${USER}@${SASL_HOST}/${GSSAPI_DB}?authMechanism=GSSAPI" +USER=$(node -p "encodeURIComponent(process.env.PRINCIPAL_BUILD)") +export MONGODB_URI="mongodb://${USER}@${SASL_HOST_BUILD}/${GSSAPI_DB}?authMechanism=GSSAPI" set -o xtrace diff --git a/README.md b/README.md index 00a05829f89..4ddd9795d5a 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Change history can be found in [`HISTORY.md`](https://github.com/mongodb/node-mo ### Compatibility -The driver currently supports 4.2+ servers. +The driver currently supports 4.4+ servers. For exhaustive server and runtime version compatibility matrices, please refer to the following links: diff --git a/src/bulk/common.ts b/src/bulk/common.ts index 77727cd9438..e1a7308d4aa 100644 --- a/src/bulk/common.ts +++ b/src/bulk/common.ts @@ -1043,7 +1043,7 @@ export abstract class BulkOperationBase { * // Add a replaceOne * bulkOp.find({ i: 9 }).replaceOne({writeConcern: { j: 10 }}); * - * // Update using a pipeline (requires Mongodb 4.2 or higher) + * // Update using a pipeline * bulk.find({ k: 11, y: { $exists: true }, z: { $exists: true } }).updateOne([ * { $set: { total: { $sum: [ '$y', '$z' ] } } } * ]); diff --git a/src/cmap/auth/mongo_credentials.ts b/src/cmap/auth/mongo_credentials.ts index f8d7e33c95c..6889414e496 100644 --- a/src/cmap/auth/mongo_credentials.ts +++ b/src/cmap/auth/mongo_credentials.ts @@ -25,7 +25,6 @@ function getDefaultAuthMechanism(hello: Document | null): AuthMechanism { } } - // Default auth mechanism for 4.0 and higher. return AuthMechanism.MONGODB_SCRAM_SHA256; } diff --git a/src/cmap/auth/mongodb_aws.ts b/src/cmap/auth/mongodb_aws.ts index 422beb3dbd2..56c1fca74d2 100644 --- a/src/cmap/auth/mongodb_aws.ts +++ b/src/cmap/auth/mongodb_aws.ts @@ -1,11 +1,7 @@ import { type Binary, type BSONSerializeOptions, ByteUtils } from '../../bson'; import * as BSON from '../../bson'; -import { - MongoCompatibilityError, - MongoMissingCredentialsError, - MongoRuntimeError -} from '../../error'; -import { maxWireVersion, ns, randomBytes } from '../../utils'; +import { MongoMissingCredentialsError, MongoRuntimeError } from '../../error'; +import { ns, randomBytes } from '../../utils'; import { type AuthContext, AuthProvider } from './auth_provider'; import { type AWSCredentialProvider, @@ -45,12 +41,6 @@ export class MongoDBAWS extends AuthProvider { throw new MongoMissingCredentialsError('AuthContext must provide credentials.'); } - if (maxWireVersion(connection) < 9) { - throw new MongoCompatibilityError( - 'MONGODB-AWS authentication requires MongoDB version 4.4 or later' - ); - } - authContext.credentials = await makeTempCredentials( authContext.credentials, this.credentialFetcher diff --git a/src/cmap/command_monitoring_events.ts b/src/cmap/command_monitoring_events.ts index 437ecd7b920..a8372b52de9 100644 --- a/src/cmap/command_monitoring_events.ts +++ b/src/cmap/command_monitoring_events.ts @@ -32,7 +32,7 @@ export class CommandStartedEvent { /** * Server generated connection id * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" - * from the server on 4.2+. + * from the server. */ serverConnectionId: bigint | null; serviceId?: ObjectId; @@ -88,7 +88,7 @@ export class CommandSucceededEvent { connectionId?: string | number; /** * Server generated connection id - * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server on 4.2+. + * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server. */ serverConnectionId: bigint | null; requestId: number; @@ -148,7 +148,7 @@ export class CommandFailedEvent { connectionId?: string | number; /** * Server generated connection id - * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server on 4.2+. + * Distinct from the connection id and is returned by the hello or legacy hello response as "connectionId" from the server. */ serverConnectionId: bigint | null; requestId: number; diff --git a/src/cmap/connect.ts b/src/cmap/connect.ts index 35d3d622f9c..5b6349affeb 100644 --- a/src/cmap/connect.ts +++ b/src/cmap/connect.ts @@ -174,7 +174,7 @@ export async function performInitialHandshake( if (error instanceof MongoError) { error.addErrorLabel(MongoErrorLabel.HandshakeError); - if (needsRetryableWriteLabel(error, response.maxWireVersion, conn.description.type)) { + if (needsRetryableWriteLabel(error)) { error.addErrorLabel(MongoErrorLabel.RetryableWriteError); } } diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index f8cc3b2d95e..7823e3124fd 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -286,7 +286,9 @@ export class Connection extends TypedEventEmitter { private get supportsOpMsg(): boolean { return ( this.description != null && - // TODO(NODE-6672,NODE-6287): This guard is primarily for maxWireVersion = 0 + // OP_MSG was introduced in server 3.6 (wire version 6). This also guards + // against the pre-handshake case where maxWireVersion() returns 0. + // TODO(NODE-6672,NODE-6287): remove this helper once OP_QUERY support is dropped maxWireVersion(this) >= 6 && !this.description.__nodejs_mock_server__ ); diff --git a/src/cmap/wire_protocol/constants.ts b/src/cmap/wire_protocol/constants.ts index aa689033e18..108b9fe4cdf 100644 --- a/src/cmap/wire_protocol/constants.ts +++ b/src/cmap/wire_protocol/constants.ts @@ -1,8 +1,8 @@ -export const MIN_SUPPORTED_SERVER_VERSION = '4.2'; +export const MIN_SUPPORTED_SERVER_VERSION = '4.4'; export const MAX_SUPPORTED_SERVER_VERSION = '9.0'; export const MIN_SUPPORTED_SNAPSHOT_READS_WIRE_VERSION = 13; export const MIN_SUPPORTED_SNAPSHOT_READS_SERVER_VERSION = '5.0'; -export const MIN_SUPPORTED_WIRE_VERSION = 8; +export const MIN_SUPPORTED_WIRE_VERSION = 9; export const MAX_SUPPORTED_WIRE_VERSION = 29; export const MIN_SUPPORTED_QE_WIRE_VERSION = 21; export const MIN_SUPPORTED_QE_SERVER_VERSION = '7.0'; diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index 693e1204d81..f5f0b14d99f 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -126,11 +126,6 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { maxAwaitTimeMS?: number; /** * Comment to apply to the operation. - * - * In server versions pre-4.4, 'comment' must be string. A server - * error will be thrown if any other type is provided. - * - * In server versions 4.4 and above, 'comment' can be any valid BSON type. */ comment?: unknown; /** diff --git a/src/error.ts b/src/error.ts index e17e3e71ebb..37979e87a83 100644 --- a/src/error.ts +++ b/src/error.ts @@ -3,7 +3,6 @@ import { type ClientBulkWriteError, type ClientBulkWriteResult } from './operations/client_bulk_write/common'; -import type { ServerType } from './sdam/common'; import type { TopologyVersion } from './sdam/server_description'; import type { TopologyDescription } from './sdam/topology_description'; @@ -1394,23 +1393,13 @@ const RETRYABLE_READ_ERROR_CODES = new Set([ // see: https://github.com/mongodb/specifications/blob/master/source/retryable-writes/retryable-writes.md#terms const RETRYABLE_WRITE_ERROR_CODES = RETRYABLE_READ_ERROR_CODES; -export function needsRetryableWriteLabel( - error: Error, - maxWireVersion: number, - serverType: ServerType -): boolean { - // pre-4.4 server, then the driver adds an error label for every valid case - // execute operation will only inspect the label, code/message logic is handled here +export function needsRetryableWriteLabel(error: Error): boolean { if (error instanceof MongoNetworkError) { return true; } - if (error instanceof MongoError) { - if ( - (maxWireVersion >= 9 || isRetryableWriteError(error)) && - !error.hasErrorLabel(MongoErrorLabel.HandshakeError) - ) { - // If we already have the error label no need to add it again. 4.4+ servers add the label. + if (!error.hasErrorLabel(MongoErrorLabel.HandshakeError)) { + // If we already have the error label no need to add it again. servers add the label. // In the case where we have a handshake error, need to fall down to the logic checking // the codes. return false; @@ -1418,10 +1407,6 @@ export function needsRetryableWriteLabel( } if (error instanceof MongoWriteConcernError) { - if (serverType === 'Mongos' && maxWireVersion < 9) { - // use original top-level code from server response - return RETRYABLE_WRITE_ERROR_CODES.has(error.result.code ?? 0); - } const code = error.result.writeConcernError.code ?? Number(error.code); return RETRYABLE_WRITE_ERROR_CODES.has(Number.isNaN(code) ? 0 : code); } @@ -1551,8 +1536,11 @@ export function isResumableError(error?: Error, wireVersion?: number): boolean { return true; } + // wireVersion of 0 is possible when the server version is unknown (e.g heartbeat failure), so despite + // all supported servers being wire version 9+, the >= 9 bound must stay to route "unknown" to the + // code-list fallback below to maintain parity. if (wireVersion != null && wireVersion >= 9) { - // DRIVERS-1308: For 4.4 drivers running against 4.4 servers, drivers will add a special case to treat the CursorNotFound error code as resumable + // DRIVERS-1308: Drivers will add a special case to treat the CursorNotFound error code as resumable if (error.code === MONGODB_ERROR_CODES.CursorNotFound) { return true; } diff --git a/src/gridfs/download.ts b/src/gridfs/download.ts index fb6691cb8cd..b391aa1c209 100644 --- a/src/gridfs/download.ts +++ b/src/gridfs/download.ts @@ -351,7 +351,7 @@ function init(stream: GridFSBucketReadStream): void { const filter: Document = { files_id: doc._id }; - // Currently (MongoDB 3.4.4) skip function does not support the index, + // Currently the skip function does not support the index, // it needs to retrieve all the documents first and then skip them. (CS-25811) // As work around we use $gte on the "n" field. if (stream.s.options && stream.s.options.start != null) { diff --git a/src/operations/command.ts b/src/operations/command.ts index da499fa685b..ebaba8607ea 100644 --- a/src/operations/command.ts +++ b/src/operations/command.ts @@ -46,11 +46,6 @@ export interface CommandOperationOptions maxTimeMS?: number; /** * Comment to apply to the operation. - * - * In server versions pre-4.4, 'comment' must be string. A server - * error will be thrown if any other type is provided. - * - * In server versions 4.4 and above, 'comment' can be any valid BSON type. */ comment?: unknown; // Admin command overrides. diff --git a/src/operations/delete.ts b/src/operations/delete.ts index d27afc664be..78a7129159a 100644 --- a/src/operations/delete.ts +++ b/src/operations/delete.ts @@ -2,9 +2,9 @@ import type { Document } from '../bson'; import { makeDocumentSequence } from '../cmap/commands'; import { type Connection } from '../cmap/connection'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; -import { MongoCompatibilityError, MongoServerError } from '../error'; +import { MongoServerError } from '../error'; import type { ClientSession } from '../sessions'; -import { maxWireVersion, type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils'; +import { type MongoDBCollectionNamespace, type MongoDBNamespace } from '../utils'; import { type WriteConcernOptions } from '../write_concern'; import { type CollationOptions, CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects, type Hint } from './operation'; @@ -74,7 +74,7 @@ export class DeleteOperation extends CommandOperation { return this.statements.every(op => (op.limit != null ? op.limit > 0 : true)); } - override buildCommandDocument(connection: Connection, _session?: ClientSession): Document { + override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document { const options = this.options; const ordered = typeof options.ordered === 'boolean' ? options.ordered : true; @@ -96,15 +96,6 @@ export class DeleteOperation extends CommandOperation { command.comment = options.comment; } - const unacknowledgedWrite = this.writeConcern && this.writeConcern.w === 0; - if (unacknowledgedWrite && maxWireVersion(connection) < 9) { - if (this.statements.find((o: Document) => o.hint)) { - throw new MongoCompatibilityError( - `hint for the delete command is only supported on MongoDB 4.4+` - ); - } - } - return command; } } diff --git a/src/operations/find_and_modify.ts b/src/operations/find_and_modify.ts index a35e288dd47..8ed9a6a0514 100644 --- a/src/operations/find_and_modify.ts +++ b/src/operations/find_and_modify.ts @@ -2,11 +2,11 @@ import { type Connection } from '..'; import type { Document } from '../bson'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Collection } from '../collection'; -import { MongoCompatibilityError, MongoInvalidArgumentError } from '../error'; +import { MongoInvalidArgumentError } from '../error'; import { ReadPreference } from '../read_preference'; import type { ClientSession } from '../sessions'; import { formatSort, type Sort, type SortForCmd } from '../sort'; -import { decorateWithCollation, hasAtomicOperators, maxWireVersion } from '../utils'; +import { decorateWithCollation, hasAtomicOperators } from '../utils'; import { type WriteConcern, type WriteConcernSettings } from '../write_concern'; import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; @@ -97,11 +97,6 @@ interface FindAndModifyCmdBase { writeConcern?: WriteConcern | WriteConcernSettings; /** * Comment to apply to the operation. - * - * In server versions pre-4.4, 'comment' must be string. A server - * error will be thrown if any other type is provided. - * - * In server versions 4.4 and above, 'comment' can be any valid BSON type. */ comment?: unknown; } @@ -146,7 +141,7 @@ export class FindAndModifyOperation extends CommandOperation { } override buildCommandDocument( - connection: Connection, + _connection: Connection, _session?: ClientSession ): Document & FindAndModifyCmdBase { const options = this.options; @@ -191,13 +186,6 @@ export class FindAndModifyOperation extends CommandOperation { decorateWithCollation(command, options); if (options.hint) { - const unacknowledgedWrite = this.writeConcern?.w === 0; - if (unacknowledgedWrite && maxWireVersion(connection) < 9) { - throw new MongoCompatibilityError( - 'hint for the findAndModify command is only supported on MongoDB 4.4+' - ); - } - command.hint = options.hint; } diff --git a/src/operations/get_more.ts b/src/operations/get_more.ts index 4e94020cd7e..064a1cb0e5f 100644 --- a/src/operations/get_more.ts +++ b/src/operations/get_more.ts @@ -4,7 +4,7 @@ import { CursorResponse } from '../cmap/wire_protocol/responses'; import { MongoRuntimeError } from '../error'; import type { Server, ServerCommandOptions } from '../sdam/server'; import { type TimeoutContext } from '../timeout'; -import { maxWireVersion, type MongoDBNamespace } from '../utils'; +import { type MongoDBNamespace } from '../utils'; import { AbstractOperation, Aspect, defineAspects, type OperationOptions } from './operation'; /** @internal */ @@ -13,8 +13,6 @@ export interface GetMoreOptions extends OperationOptions { batchSize?: number; /** * Comment to apply to the operation. - * - * getMore only supports 'comment' in server versions 4.4 and above. */ comment?: unknown; /** Number of milliseconds to wait before aborting the query. */ @@ -55,7 +53,7 @@ export class GetMoreOperation extends AbstractOperation { return 'getMore' as const; } - override buildCommand(connection: Connection): Document { + override buildCommand(_connection: Connection): Document { if (this.cursorId == null || this.cursorId.isZero()) { throw new MongoRuntimeError('Unable to iterate cursor with no id'); } @@ -82,7 +80,7 @@ export class GetMoreOperation extends AbstractOperation { // we check for undefined specifically here to allow falsy values // eslint-disable-next-line no-restricted-syntax - if (this.options.comment !== undefined && maxWireVersion(connection) >= 9) { + if (this.options.comment !== undefined) { getMoreCmd.comment = this.options.comment; } diff --git a/src/operations/indexes.ts b/src/operations/indexes.ts index f6354dcf1ad..d6ae371f702 100644 --- a/src/operations/indexes.ts +++ b/src/operations/indexes.ts @@ -3,9 +3,8 @@ import { type Connection } from '../cmap/connection'; import { CursorResponse, MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Collection } from '../collection'; import { type AbstractCursorOptions } from '../cursor/abstract_cursor'; -import { MongoCompatibilityError } from '../error'; import { type OneOrMore } from '../mongo_types'; -import { isObject, maxWireVersion, type MongoDBNamespace } from '../utils'; +import { isObject, type MongoDBNamespace } from '../utils'; import { type CollationOptions, CommandOperation, @@ -138,7 +137,7 @@ export interface CreateIndexesOptions extends Omit { return 'createIndexes'; } - override buildCommandDocument(connection: Connection): Document { + override buildCommandDocument(_connection: Connection): Document { const options = this.options; const indexes = this.indexes; - const serverWireVersion = maxWireVersion(connection); - const cmd: Document = { createIndexes: this.collectionName, indexes }; if (options.commitQuorum != null) { - if (serverWireVersion < 9) { - throw new MongoCompatibilityError( - 'Option `commitQuorum` for `createIndexes` not supported on servers < 4.4' - ); - } cmd.commitQuorum = options.commitQuorum; } return cmd; @@ -385,16 +377,14 @@ export class ListIndexesOperation extends CommandOperation { return 'listIndexes' as const; } - override buildCommandDocument(connection: Connection): Document { - const serverWireVersion = maxWireVersion(connection); - + override buildCommandDocument(_connection: Connection): Document { const cursor = this.options.batchSize ? { batchSize: this.options.batchSize } : {}; const command: Document = { listIndexes: this.collectionNamespace.collection, cursor }; // we check for undefined specifically here to allow falsy values // eslint-disable-next-line no-restricted-syntax - if (serverWireVersion >= 9 && this.options.comment !== undefined) { + if (this.options.comment !== undefined) { command.comment = this.options.comment; } diff --git a/src/operations/list_collections.ts b/src/operations/list_collections.ts index df38c954cb9..ff1bc6a9f09 100644 --- a/src/operations/list_collections.ts +++ b/src/operations/list_collections.ts @@ -4,7 +4,6 @@ import { CursorResponse, ExplainedCursorResponse } from '../cmap/wire_protocol/r import { type CursorTimeoutContext, type CursorTimeoutMode } from '../cursor/abstract_cursor'; import type { Db } from '../db'; import { type Abortable } from '../mongo_types'; -import { maxWireVersion } from '../utils'; import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; @@ -12,11 +11,11 @@ import { Aspect, defineAspects } from './operation'; export interface ListCollectionsOptions extends Omit, Abortable { - /** Since 4.0: If true, will only return the collection name in the response, and will omit additional info */ + /** If true, will only return the collection name in the response, and will omit additional info */ nameOnly?: boolean; - /** Since 4.0: If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */ + /** If true and nameOnly is true, allows a user without the required privilege (i.e. listCollections action on the database) to run the command when access control is enforced. */ authorizedCollections?: boolean; - /** The batchSize for the returned command cursor or if pre 2.8 the systems batch collection */ + /** The batchSize for the returned command cursor */ batchSize?: number; /** @internal */ timeoutMode?: CursorTimeoutMode; @@ -63,7 +62,7 @@ export class ListCollectionsOperation extends CommandOperation { return 'listCollections' as const; } - override buildCommandDocument(connection: Connection): Document { + override buildCommandDocument(_connection: Connection): Document { const command: Document = { listCollections: 1, filter: this.filter, @@ -74,7 +73,7 @@ export class ListCollectionsOperation extends CommandOperation { // we check for undefined specifically here to allow falsy values // eslint-disable-next-line no-restricted-syntax - if (maxWireVersion(connection) >= 9 && this.options.comment !== undefined) { + if (this.options.comment !== undefined) { command.comment = this.options.comment; } diff --git a/src/operations/list_databases.ts b/src/operations/list_databases.ts index b9f4e97dda7..1867471a6cb 100644 --- a/src/operations/list_databases.ts +++ b/src/operations/list_databases.ts @@ -3,7 +3,7 @@ import type { Document } from '../bson'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; import type { Db } from '../db'; import type { ClientSession } from '../sessions'; -import { maxWireVersion, MongoDBNamespace } from '../utils'; +import { MongoDBNamespace } from '../utils'; import { CommandOperation, type CommandOperationOptions } from './command'; import { Aspect, defineAspects } from './operation'; @@ -40,7 +40,7 @@ export class ListDatabasesOperation extends CommandOperation= 9 && this.options.comment !== undefined) { + if (this.options.comment !== undefined) { cmd.comment = this.options.comment; } diff --git a/src/operations/validate_collection.ts b/src/operations/validate_collection.ts index fb5fec8dc4e..1db92a3f0a6 100644 --- a/src/operations/validate_collection.ts +++ b/src/operations/validate_collection.ts @@ -8,7 +8,7 @@ import { CommandOperation, type CommandOperationOptions } from './command'; /** @public */ export interface ValidateCollectionOptions extends Omit { - /** Validates a collection in the background, without interrupting read or write traffic (only in MongoDB 4.4+) */ + /** Validates a collection in the background, without interrupting read or write traffic */ background?: boolean; } diff --git a/src/sdam/server.ts b/src/sdam/server.ts index 14b6455f1f1..45c1c4127e2 100644 --- a/src/sdam/server.ts +++ b/src/sdam/server.ts @@ -494,7 +494,7 @@ export class Server extends TypedEventEmitter { } else { if ( (isRetryableWritesEnabled(this.topology) || isTransactionCommand(cmd)) && - needsRetryableWriteLabel(error, maxWireVersion(this), this.description.type) && + needsRetryableWriteLabel(error) && !inActiveTransaction(session, cmd) ) { error.addErrorLabel(MongoErrorLabel.RetryableWriteError); diff --git a/src/utils.ts b/src/utils.ts index 50c0ddf0a20..d9a96115fc8 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -343,9 +343,7 @@ export function maxWireVersion(handshakeAware?: Connection | Topology | Server): // object being checked will be a connection, and we will have a hello response on // it. For other cases, such as retryable writes, the object will be a server or // topology, and there will be no hello response on those objects, so we return - // the max wire version so we support retryability. Once we have a min supported - // wire version of 9, then the needsRetryableWriteLabel() check can remove the - // usage of passing the wire version into it. + // the max wire version so we support retryability. if (handshakeAware.loadBalanced) { return MAX_SUPPORTED_WIRE_VERSION; } diff --git a/test/integration/change-streams/change_stream.test.ts b/test/integration/change-streams/change_stream.test.ts index bdcdfa6b829..0e7f144de88 100644 --- a/test/integration/change-streams/change_stream.test.ts +++ b/test/integration/change-streams/change_stream.test.ts @@ -2,7 +2,7 @@ import { strict as assert } from 'assert'; import { Long, UUID } from 'bson'; import { expect } from 'chai'; import { on, once } from 'events'; -import { gte, lt } from 'semver'; +import { gte } from 'semver'; import * as sinon from 'sinon'; import { PassThrough } from 'stream'; import { setTimeout } from 'timers'; @@ -37,9 +37,6 @@ const initIteratorMode = async (cs: ChangeStream) => { return; }; -const is4_2Server = (serverVersion: string) => - gte(serverVersion, '4.2.0') && lt(serverVersion, '4.3.0'); - // Define the pipeline processing changes const pipeline = [ { $addFields: { addedField: 'This is a field added using $addFields' } }, @@ -1130,9 +1127,7 @@ describe('Change Streams', function () { const unresumableErrorCode = 1000; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -1947,9 +1942,7 @@ describe('Change Streams', function () { afterEach(async function () { await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: 'off' } as FailCommandFailPoint); @@ -1970,9 +1963,7 @@ describe('Change Streams', function () { }); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2002,9 +1993,7 @@ describe('Change Streams', function () { }); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2036,9 +2025,7 @@ describe('Change Streams', function () { }); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2167,9 +2154,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2195,9 +2180,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 5 }, data: { failCommands: ['getMore'], @@ -2234,9 +2217,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2265,9 +2246,7 @@ describe('ChangeStream resumability', function () { const unresumableErrorCode = 1000; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2353,9 +2332,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2381,9 +2358,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 5 }, data: { failCommands: ['getMore'], @@ -2420,9 +2395,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2451,9 +2424,7 @@ describe('ChangeStream resumability', function () { const unresumableErrorCode = 1000; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2507,9 +2478,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2542,9 +2511,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 5 }, data: { failCommands: ['getMore'], @@ -2581,9 +2548,7 @@ describe('ChangeStream resumability', function () { await initIteratorMode(changeStream); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2612,9 +2577,7 @@ describe('ChangeStream resumability', function () { const unresumableErrorCode = 1000; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2700,9 +2663,7 @@ describe('ChangeStream resumability', function () { await collection.insertMany(docs); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2735,9 +2696,7 @@ describe('ChangeStream resumability', function () { const changeStreamIterator = changeStream[Symbol.asyncIterator](); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2769,9 +2728,7 @@ describe('ChangeStream resumability', function () { const unresumableErrorCode = 1000; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2868,9 +2825,7 @@ describe('ChangeStream resumability', function () { changeStream = collection.watch([]); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2898,9 +2853,7 @@ describe('ChangeStream resumability', function () { changeStream = collection.watch([]); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 5 }, data: { failCommands: ['getMore'], @@ -2938,9 +2891,7 @@ describe('ChangeStream resumability', function () { changeStream = collection.watch([], changeStreamResumeOptions); await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2972,9 +2923,7 @@ describe('ChangeStream resumability', function () { const unresumableErrorCode = 1000; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], @@ -2999,9 +2948,7 @@ describe('ChangeStream resumability', function () { const unresumableErrorCode = 237; await client.db('admin').command({ - configureFailPoint: is4_2Server(this.configuration.version) - ? 'failCommand' - : 'failGetMoreAfterCursorCheckout', + configureFailPoint: 'failGetMoreAfterCursorCheckout', mode: { times: 1 }, data: { failCommands: ['getMore'], diff --git a/test/integration/client-side-operations-timeout/client_side_operations_timeout.prose.test.ts b/test/integration/client-side-operations-timeout/client_side_operations_timeout.prose.test.ts index a256bce727c..436ad0e73d9 100644 --- a/test/integration/client-side-operations-timeout/client_side_operations_timeout.prose.test.ts +++ b/test/integration/client-side-operations-timeout/client_side_operations_timeout.prose.test.ts @@ -122,7 +122,7 @@ describe('CSOT spec prose tests', function () { context('2. maxTimeMS is not set for commands sent to mongocryptd', () => { /** - * This test MUST only be run against enterprise server versions 4.2 and higher. + * This test MUST only be run against enterprise servers. * * 1. Launch a mongocryptd process on 23000. * 1. Create a MongoClient (referred to as `client`) using the URI `mongodb://localhost:23000/?timeoutMS=1000`. diff --git a/test/integration/command-logging-and-monitoring/command_monitoring.test.ts b/test/integration/command-logging-and-monitoring/command_monitoring.test.ts index 9242770d46c..3ea3320b0a8 100644 --- a/test/integration/command-logging-and-monitoring/command_monitoring.test.ts +++ b/test/integration/command-logging-and-monitoring/command_monitoring.test.ts @@ -472,46 +472,6 @@ describe('Command Monitoring', function () { } }); - it('should ensure killcursor commands are sent on 3.0 or earlier when APM is enabled', { - metadata: { requires: { topology: ['single', 'replicaset'], mongodb: '<=3.0.x' } }, - - test: function () { - const client = this.configuration.newClient( - { writeConcern: { w: 1 } }, - { maxPoolSize: 1, monitorCommands: true } - ); - - const db = client.db(this.configuration.db); - const admindb = db.admin(); - let cursorCountBefore; - let cursorCountAfter; - - const collection = db.collection('apm_killcursor_tests'); - - // make sure collection has records (more than 2) - return collection - .insertMany([{ a: 1 }, { a: 2 }, { a: 3 }]) - .then(r => { - expect(r).to.exist; - return admindb.serverStatus(); - }) - .then(result => { - cursorCountBefore = result.cursors.clientCursors_size; - const cursor = collection.find({}).limit(2); - return cursor.toArray().then(r => { - expect(r).to.exist; - return cursor.close(); - }); - }) - .then(() => admindb.serverStatus()) - .then(result => { - cursorCountAfter = result.cursors.clientCursors_size; - expect(cursorCountBefore).to.equal(cursorCountAfter); - return client.close(); - }); - } - }); - it('should correctly decorate the apm result for aggregation with cursorId', async function () { const started = []; const succeeded = []; diff --git a/test/integration/connection-monitoring-and-pooling/rtt_pinger.test.ts b/test/integration/connection-monitoring-and-pooling/rtt_pinger.test.ts index 5b659290ef6..54cc8a292e9 100644 --- a/test/integration/connection-monitoring-and-pooling/rtt_pinger.test.ts +++ b/test/integration/connection-monitoring-and-pooling/rtt_pinger.test.ts @@ -109,8 +109,8 @@ describe('class RTTPinger', () => { const rttPingers = await getRTTPingers(client); // Fake pre-hello server. - // Hello was back-ported to feature versions of the server so we would need to pin - // versions prior to 4.4.2, 4.2.10, 4.0.21, and 3.6.21 to integration test + // Hello was back-ported to feature versions of the server so we would need to pin patch + // versions prior to 4.4.2 to integration test for (const rtt of rttPingers) rtt.connection.helloOk = false; const spies = rttPingers.map(rtt => sinon.spy(rtt.connection, 'command')); diff --git a/test/integration/connections-survive-step-down/connections_survive_step_down.prose.test.ts b/test/integration/connections-survive-step-down/connections_survive_step_down.prose.test.ts index 3ba24d95870..8bf05d073cf 100644 --- a/test/integration/connections-survive-step-down/connections_survive_step_down.prose.test.ts +++ b/test/integration/connections-survive-step-down/connections_survive_step_down.prose.test.ts @@ -44,7 +44,7 @@ describe('Connections Survive Primary Step Down - prose', function () { }); context('getMore Iteration', { requires: { topology: ['replicaset'] } }, () => { - // This test requires a replica set with server version 4.2 or higher. + // This test requires a replica set. let cursor: FindCursor; afterEach(() => cursor.close()); @@ -91,7 +91,7 @@ describe('Connections Survive Primary Step Down - prose', function () { }); context('Not Primary - Keep Connection Pool', { requires: { topology: ['replicaset'] } }, () => { - // This test requires a replica set with server version 4.2 or higher. + // This test requires a replica set. // - Set the following fail point: ``{configureFailPoint: "failCommand", mode: {times: 1}, data: {failCommands: ["insert"], errorCode: 10107}}`` const failPoint: FailCommandFailPoint = { diff --git a/test/integration/crud/find.test.ts b/test/integration/crud/find.test.ts index 9e6ed994f13..2b24254e2db 100644 --- a/test/integration/crud/find.test.ts +++ b/test/integration/crud/find.test.ts @@ -1,14 +1,7 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; -import { - Code, - Long, - type MongoClient, - MongoServerError, - ObjectId, - ReturnDocument -} from '../../mongodb'; +import { Long, type MongoClient, MongoServerError, ObjectId, ReturnDocument } from '../../mongodb'; import { assert as test, filterForCommands } from '../shared'; describe('Find', function () { @@ -266,31 +259,6 @@ describe('Find', function () { test.equal(0, documents.length); }); - it('should correctly perform find by $where', { - metadata: { requires: { mongodb: '4.2.x' } }, - test: async function () { - const db = client.db(this.configuration.db); - const collection = await db.createCollection('test_where'); - await collection.insertMany( - [{ a: 1 }, { a: 2 }, { a: 3 }], - this.configuration.writeConcernMax() - ); - - const count = await collection.countDocuments(); - test.equal(3, count); - - // @ts-expect-error: $where no longer supports Code - const documentsGT2 = await collection.find({ $where: new Code('this.a > 2') }).toArray(); - test.equal(1, documentsGT2.length); - - const documentsGT1 = await collection - // @ts-expect-error: $where no longer supports Code - .find({ $where: new Code('this.a > i', { i: 1 }) }) - .toArray(); - test.equal(2, documentsGT1.length); - } - }); - it('should correctly perform finds with hint turned on', async function () { const configuration = this.configuration; const p_client = configuration.newClient(configuration.writeConcernMax(), { diff --git a/test/integration/enumerate_collections.test.ts b/test/integration/enumerate_collections.test.ts index 85c043c29fb..161fac6a3b1 100644 --- a/test/integration/enumerate_collections.test.ts +++ b/test/integration/enumerate_collections.test.ts @@ -8,32 +8,6 @@ describe('listCollections', () => { databaseName: 'database0', documents: [{ _id: 1, x: 11 }] }) - .test( - new TestBuilder('listCollections should not send comment for server versions < 4.4') - .runOnRequirement({ maxServerVersion: '4.3.99' }) - .operation({ - name: 'listCollections', - arguments: { - filter: {}, - comment: 'string value' - }, - object: 'database0' - }) - .expectEvents({ - client: 'client0', - events: [ - { - commandStartedEvent: { - command: { - listCollections: 1, - comment: { $$exists: false } - } - } - } - ] - }) - .toJSON() - ) .test( new TestBuilder('listCollections should send string comment for server versions >= 4.4') .runOnRequirement({ minServerVersion: '4.4.0' }) diff --git a/test/integration/enumerate_databases.test.ts b/test/integration/enumerate_databases.test.ts index 0b52ade1303..f1967b67a96 100644 --- a/test/integration/enumerate_databases.test.ts +++ b/test/integration/enumerate_databases.test.ts @@ -192,32 +192,6 @@ describe('listDatabases()', function () { databaseName: 'database0', documents: [{ _id: 1, x: 11 }] }) - .test( - new TestBuilder('listDatabases should not send comment for server versions < 4.4') - .runOnRequirement({ maxServerVersion: '4.3.99' }) - .operation({ - name: 'listDatabases', - arguments: { - filter: {}, - comment: 'string value' - }, - object: 'client0' - }) - .expectEvents({ - client: 'client0', - events: [ - { - commandStartedEvent: { - command: { - listDatabases: 1, - comment: { $$exists: false } - } - } - } - ] - }) - .toJSON() - ) .test( new TestBuilder('listDatabases should send string comment for server versions >= 4.4') .runOnRequirement({ minServerVersion: '4.4.0' }) diff --git a/test/integration/enumerate_indexes.test.ts b/test/integration/enumerate_indexes.test.ts index 8e8793d6040..d2a5114e6d8 100644 --- a/test/integration/enumerate_indexes.test.ts +++ b/test/integration/enumerate_indexes.test.ts @@ -8,32 +8,6 @@ describe('listIndexes()', () => { databaseName: 'database0', documents: [{ _id: 1, x: 11 }] }) - .test( - new TestBuilder('listIndexes should not send comment for server versions < 4.4') - .runOnRequirement({ maxServerVersion: '4.3.99' }) - .operation({ - name: 'listIndexes', - arguments: { - filter: {}, - comment: 'string value' - }, - object: 'collection0' - }) - .expectEvents({ - client: 'client0', - events: [ - { - commandStartedEvent: { - command: { - listIndexes: 'collection0', - comment: { $$exists: false } - } - } - } - ] - }) - .toJSON() - ) .test( new TestBuilder('listIndexes should send string comment for server versions >= 4.4') .runOnRequirement({ minServerVersion: '4.4.0' }) diff --git a/test/integration/index_management.test.ts b/test/integration/index_management.test.ts index 100cb1c9a5a..abbb5e8899c 100644 --- a/test/integration/index_management.test.ts +++ b/test/integration/index_management.test.ts @@ -728,36 +728,6 @@ describe('Indexes', function () { await client.close(); }); - function throwErrorTest(testCommand: (db: Db, collection: Collection) => Promise) { - return { - metadata: { requires: { mongodb: '<4.4' } }, - test: async function () { - const db = client.db('test'); - const collection = db.collection('commitQuorum'); - const err = await testCommand(db, collection).catch(e => e); - expect(err.message).to.equal( - 'Option `commitQuorum` for `createIndexes` not supported on servers < 4.4' - ); - } - }; - } - it( - 'should throw an error if commitQuorum specified on db.createIndex', - throwErrorTest((db, collection) => - db.createIndex(collection.collectionName, 'a', { commitQuorum: 'all' }) - ) - ); - it( - 'should throw an error if commitQuorum specified on collection.createIndex', - throwErrorTest((db, collection) => collection.createIndex('a', { commitQuorum: 'all' })) - ); - it( - 'should throw an error if commitQuorum specified on collection.createIndexes', - throwErrorTest((db, collection) => - collection.createIndexes([{ key: { a: 1 } }, { key: { b: 1 } }], { commitQuorum: 'all' }) - ) - ); - function commitQuorumTest( testCommand: (db: Db, collection: Collection) => Promise ): any { diff --git a/test/integration/retryable-reads/retryable_reads.spec.prose.test.ts b/test/integration/retryable-reads/retryable_reads.spec.prose.test.ts index ee95fad6cbf..fc1c17e2677 100644 --- a/test/integration/retryable-reads/retryable_reads.spec.prose.test.ts +++ b/test/integration/retryable-reads/retryable_reads.spec.prose.test.ts @@ -30,7 +30,6 @@ describe('Retryable Reads Spec Prose', () => { describe('PoolClearedError Retryability Test', () => { // This test will be used to ensure drivers properly retry after encountering PoolClearedErrors. // It MUST be implemented by any driver that implements the CMAP specification. - // This test requires MongoDB 4.2.9+ for blockConnection support in the failpoint. let cmapEvents: Array<{ name: string; event: Record }>; let commandStartedEvents: Array>; diff --git a/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts b/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts index 430f263011e..32082873a2f 100644 --- a/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts +++ b/test/integration/retryable-writes/retryable_writes.spec.prose.test.ts @@ -85,7 +85,6 @@ describe('Retryable Writes Spec Prose', () => { describe('2. Test that drivers properly retry after encountering PoolClearedErrors.', () => { // This test MUST be implemented by any driver that implements the CMAP specification. - // This test requires MongoDB 4.2.9+ for blockConnection support in the failpoint. let client: MongoClient; let failPointName: string | undefined; @@ -151,7 +150,7 @@ describe('Retryable Writes Spec Prose', () => { }); it('should emit events in the expected sequence', { - metadata: { requires: { mongodb: '>=4.2.9', topology: ['replicaset', 'sharded'] } }, + metadata: { requires: { mongodb: '>=4.4.0', topology: ['replicaset', 'sharded'] } }, test: async function () { // iii. Start two threads and attempt to perform an insertOne simultaneously on both. await Promise.all([ @@ -276,7 +275,7 @@ describe('Retryable Writes Spec Prose', () => { */ it( 'when a retry attempt fails with an error labeled NoWritesPerformed, drivers MUST return the original error', - { requires: { topology: 'replicaset', mongodb: '>=4.2.9' } }, + { requires: { topology: 'replicaset', mongodb: '>=4.4.0' } }, async () => { const serverCommandStub = sinon.stub(Server.prototype, 'command'); serverCommandStub.onCall(0).rejects( @@ -310,7 +309,7 @@ describe('Retryable Writes Spec Prose', () => { // must succeed, we fail if any command failed event occurs on insert. it( 'emits a command succeeded event for write concern errors with ok: 1', - { requires: { topology: 'replicaset', mongodb: '>=4.2.9' } }, + { requires: { topology: 'replicaset', mongodb: '>=4.4.0' } }, async () => { // Generate a write concern error to assert that we get a command // suceeded event but the operation will retry because it was an diff --git a/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.prose.test.ts b/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.prose.test.ts index 1f4cec00571..4189a68a4c9 100644 --- a/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.prose.test.ts +++ b/test/integration/server-discovery-and-monitoring/server_discovery_and_monitoring.prose.test.ts @@ -94,7 +94,6 @@ describe('Server Discovery and Monitoring Prose Tests', function () { context('Connection Pool Management', function () { /* This test will be used to ensure monitors properly create and unpause connection pools when they discover servers. - This test requires failCommand appName support which is only available in MongoDB 4.2.9+. 1. Create a client with directConnection=true, appName="SDAMPoolManagementTest", and heartbeatFrequencyMS=500 (or lower if possible). 2. Verify via SDAM and CMAP event monitoring that a ConnectionPoolReadyEvent occurs after the first ServerHeartbeatSucceededEvent event does. 3. Enable the following failpoint: @@ -153,7 +152,7 @@ describe('Server Discovery and Monitoring Prose Tests', function () { }); it('ensure monitors properly create and unpause connection pools when they discover servers', { - metadata: { requires: { mongodb: '>=4.2.9', topology: '!load-balanced' } }, + metadata: { requires: { mongodb: '>=4.4.0', topology: '!load-balanced' } }, test: async function () { await client.connect(); expect(events.shift()).to.equal(SERVER_HEARTBEAT_SUCCEEDED); diff --git a/test/integration/server-selection/server_selection.prose.operation_count.test.ts b/test/integration/server-selection/server_selection.prose.operation_count.test.ts index b4a7d9bf47b..ca3a42f4274 100644 --- a/test/integration/server-selection/server_selection.prose.operation_count.test.ts +++ b/test/integration/server-selection/server_selection.prose.operation_count.test.ts @@ -27,8 +27,8 @@ async function runTaskGroup(collection: Collection, count: 10 | 100 | 1000) { } } -// Step 1: Configure a sharded cluster with two mongoses. Use a 4.2.9 or newer server version. -const TEST_METADATA: MongoDBMetadataUI = { requires: { mongodb: '>=4.2.9', topology: 'sharded' } }; +// Step 1: Configure a sharded cluster with two mongoses. +const TEST_METADATA: MongoDBMetadataUI = { requires: { mongodb: '>=4.4.0', topology: 'sharded' } }; describe('operationCount-based Selection Within Latency Window - Prose Test', function () { let client: MongoClient; diff --git a/test/integration/server-selection/server_selection.prose.sharded_retryable_reads.test.ts b/test/integration/server-selection/server_selection.prose.sharded_retryable_reads.test.ts index 3b72fe93eb1..9312c0dc33d 100644 --- a/test/integration/server-selection/server_selection.prose.sharded_retryable_reads.test.ts +++ b/test/integration/server-selection/server_selection.prose.sharded_retryable_reads.test.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import type { CommandFailedEvent, CommandSucceededEvent } from '../../mongodb'; -const TEST_METADATA = { requires: { mongodb: '>=4.2.9', topology: 'sharded' } }; +const TEST_METADATA = { requires: { mongodb: '>=4.4.0', topology: 'sharded' } }; const FAIL_COMMAND = { configureFailPoint: 'failCommand', mode: { times: 1 }, diff --git a/test/integration/sessions/sessions.prose.test.ts b/test/integration/sessions/sessions.prose.test.ts index b6be8d763ed..ed971612afa 100644 --- a/test/integration/sessions/sessions.prose.test.ts +++ b/test/integration/sessions/sessions.prose.test.ts @@ -129,7 +129,6 @@ describe('Sessions Prose Tests', () => { /** * Since all regular 3.6+ servers support sessions, the prose tests which test for * session non-support SHOULD use a mongocryptd server as the test server - * (available with server versions 4.2+) * * As part of the test setup for these cases, create a MongoClient pointed at the test server * with the options specified in the test case and verify that the test server does NOT define a diff --git a/test/manual/kerberos.test.ts b/test/manual/kerberos.test.ts index 6eafa560a05..767a2ddb83d 100644 --- a/test/manual/kerberos.test.ts +++ b/test/manual/kerberos.test.ts @@ -12,8 +12,13 @@ const expect = chai.expect; chai.use(require('sinon-chai').default); async function verifyKerberosAuthentication(client) { - const docs = await client.db('kerberos').collection('test').find().toArray(); - expect(docs).to.have.nested.property('[0].kerberos', true); + let thrown; + try { + await client.connect(); + } catch (err) { + thrown = err; + } + expect(thrown).to.not.exist; } describe('Kerberos', function () { @@ -36,16 +41,15 @@ describe('Kerberos', function () { }); const krb5Uri = process.env.MONGODB_URI; - const host = process.env.SASL_HOST; + const host = process.env.SASL_HOST_BUILD; - if (!process.env.PRINCIPAL) { - console.error('skipping Kerberos tests, PRINCIPAL environment variable is not defined'); + if (!process.env.PRINCIPAL_BUILD) { + console.error('skipping Kerberos tests, PRINCIPAL_BUILD environment variable is not defined'); return; } it('should authenticate with original uri', async function () { client = new MongoClient(krb5Uri); - await client.connect(); await verifyKerberosAuthentication(client); }); @@ -63,9 +67,8 @@ describe('Kerberos', function () { client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:forward&maxPoolSize=1` ); - await client.connect(); - expect(resolveStub.withArgs(sinon.match.any, 'CNAME')).to.be.calledOnceWith(host, 'CNAME'); await verifyKerberosAuthentication(client); + expect(resolveStub.withArgs(sinon.match.any, 'CNAME')).to.be.calledOnceWith(host, 'CNAME'); }); }); @@ -75,12 +78,11 @@ describe('Kerberos', function () { client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:${option}&maxPoolSize=1` ); - await client.connect(); + await verifyKerberosAuthentication(client); expect(resolveStub.withArgs(sinon.match.any, 'CNAME')).to.not.be.called; // There are 2 calls to establish connection, however they use the callback form of dns.lookup expect(lookupStub).to.not.be.called; - await verifyKerberosAuthentication(client); }); }); } @@ -92,13 +94,12 @@ describe('Kerberos', function () { client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:${option}&maxPoolSize=1` ); - await client.connect(); + await verifyKerberosAuthentication(client); // There are 2 calls to establish connection, however they use the callback form of dns.lookup // 1 dns.promises.lookup call in canonicalization. expect(lookupStub).to.be.calledOnce; expect(resolveStub.withArgs(sinon.match.any, 'PTR')).to.be.calledOnce; - await verifyKerberosAuthentication(client); }); }); @@ -112,7 +113,7 @@ describe('Kerberos', function () { `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:${option}&maxPoolSize=1` ); - await client.connect(); + await verifyKerberosAuthentication(client); // There are 2 calls to establish connection, however they use the callback form of dns.lookup // 1 dns.promises.lookup call in canonicalization. expect(lookupStub).to.be.calledOnce; @@ -120,7 +121,6 @@ describe('Kerberos', function () { expect(resolveStub.withArgs(sinon.match.string, 'PTR')).to.be.calledOnce; // Expect the fallback to the host name. expect(resolveStub.withArgs(sinon.match.string, 'CNAME')).to.not.be.called; - await verifyKerberosAuthentication(client); }); }); @@ -134,7 +134,7 @@ describe('Kerberos', function () { `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:${option}&maxPoolSize=1` ); - await client.connect(); + await verifyKerberosAuthentication(client); // There are 2 calls to establish connection, however they use the callback form of dns.lookup // 1 dns.promises.lookup call in canonicalization. expect(lookupStub).to.be.calledOnce; @@ -142,7 +142,6 @@ describe('Kerberos', function () { expect(resolveStub.withArgs(sinon.match.string, 'PTR')).to.be.calledOnce; // Expect the fallback to be called. expect(resolveStub.withArgs(sinon.match.string, 'CNAME')).to.be.calledOnceWith(host); - await verifyKerberosAuthentication(client); }); }); @@ -155,7 +154,7 @@ describe('Kerberos', function () { client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:${option}&maxPoolSize=1` ); - await client.connect(); + await verifyKerberosAuthentication(client); // There are 2 calls to establish connection, however they use the callback form of dns.lookup // 1 dns.promises.lookup call in canonicalization. expect(lookupStub).to.be.calledOnce; @@ -163,7 +162,6 @@ describe('Kerberos', function () { expect(resolveStub.withArgs(sinon.match.string, 'PTR')).to.be.calledOnce; // Expect the fallback to be called. expect(resolveStub.withArgs(sinon.match.string, 'CNAME')).to.be.calledOnceWith(host); - await verifyKerberosAuthentication(client); }); }); @@ -176,7 +174,7 @@ describe('Kerberos', function () { client = new MongoClient( `${krb5Uri}&authMechanismProperties=SERVICE_NAME:mongodb,CANONICALIZE_HOST_NAME:${option}&maxPoolSize=1` ); - await client.connect(); + await verifyKerberosAuthentication(client); // There are 2 calls to establish connection, however they use the callback form of dns.lookup // 1 dns.promises.lookup call in canonicalization. expect(lookupStub).to.be.calledOnce; @@ -184,7 +182,6 @@ describe('Kerberos', function () { expect(resolveStub.withArgs(sinon.match.string, 'PTR')).to.be.calledOnce; // Expect the fallback to be called. expect(resolveStub.withArgs(sinon.match.string, 'CNAME')).to.be.calledOnceWith(host); - await verifyKerberosAuthentication(client); }); }); }); @@ -222,11 +219,10 @@ describe('Kerberos', function () { it('authenticates', async function () { client = new MongoClient(`${krb5Uri}&maxPoolSize=1`, { authMechanismProperties: { - SERVICE_HOST: 'ldaptest.10gen.cc' + SERVICE_HOST: 'ldaptest.build.10gen.cc' } }); - await client.connect(); await verifyKerberosAuthentication(client); }); }); @@ -260,7 +256,7 @@ describe('Kerberos', function () { it('should fail to authenticate with bad credentials', async function () { client = new MongoClient( - krb5Uri.replace(encodeURIComponent(process.env.PRINCIPAL), 'bad%40creds.cc') + krb5Uri.replace(encodeURIComponent(process.env.PRINCIPAL_BUILD), 'bad%40creds.cc') ); const err = await client.connect().catch(e => e); expect(err.message).to.match(/Authentication failed/); diff --git a/test/manual/ldap.test.ts b/test/manual/ldap.test.ts index e110b910581..3952b2f9218 100644 --- a/test/manual/ldap.test.ts +++ b/test/manual/ldap.test.ts @@ -4,16 +4,21 @@ import * as process from 'process'; import { MongoClient } from '../mongodb'; describe('LDAP', function () { - const { SASL_USER, SASL_PASS, SASL_HOST } = process.env; + const { SASL_USER, SASL_PASS, SASL_HOST_BUILD } = process.env; - const MONGODB_URI = `mongodb://${SASL_USER}:${SASL_PASS}@${SASL_HOST}?authMechanism=plain&authSource=$external`; + const MONGODB_URI = `mongodb://${SASL_USER}:${SASL_PASS}@${SASL_HOST_BUILD}?authMechanism=plain&authSource=$external`; it('Should correctly authenticate against ldap', async function () { const client = new MongoClient(MONGODB_URI); - await client.connect(); - const doc = await client.db('ldap').collection('test').findOne(); - expect(doc).property('ldap').to.equal(true); + let thrown; + try { + await client.connect(); + } catch (error) { + thrown = error; + } + + expect(thrown).to.not.exist; await client.close(); }); diff --git a/test/spec/client-side-operations-timeout/README.md b/test/spec/client-side-operations-timeout/README.md index a960c2de219..c555187a4f1 100644 --- a/test/spec/client-side-operations-timeout/README.md +++ b/test/spec/client-side-operations-timeout/README.md @@ -58,7 +58,7 @@ for differing bulk encoding performance. ### 2. maxTimeMS is not set for commands sent to mongocryptd -This test MUST only be run against enterprise server versions 4.2 and higher. +This test MUST only be run against enterprise servers. 1. Launch a mongocryptd process on 23000. 2. Create a MongoClient (referred to as `client`) using the URI `mongodb://localhost:23000/?timeoutMS=1000`. diff --git a/test/tools/mongodb-mock/index.js b/test/tools/mongodb-mock/index.js index 11427450f77..5e1976f0b9c 100644 --- a/test/tools/mongodb-mock/index.js +++ b/test/tools/mongodb-mock/index.js @@ -18,8 +18,8 @@ const DEFAULT_HELLO = { ok: 1 }; -const DEFAULT_HELLO_42 = Object.assign({}, DEFAULT_HELLO, { - maxWireVersion: 8, +const DEFAULT_HELLO_44 = Object.assign({}, DEFAULT_HELLO, { + maxWireVersion: 9, logicalSessionTimeoutMinutes: 10 }); @@ -93,5 +93,5 @@ function cleanup(spy, callback) { module.exports = { createServer, cleanup, - HELLO: DEFAULT_HELLO_42 + HELLO: DEFAULT_HELLO_44 }; diff --git a/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts b/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts index c9abe0e5a4d..b8cf8d6c118 100644 --- a/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts +++ b/test/unit/assorted/server_discovery_and_monitoring.spec.test.ts @@ -10,6 +10,7 @@ import { HEARTBEAT_EVENTS, isRecord, LEGACY_HELLO_COMMAND, + MIN_SUPPORTED_WIRE_VERSION, MongoClient, MongoCompatibilityError, MongoError, @@ -191,6 +192,20 @@ function assertMonitoringOutcome(outcome: any): asserts outcome is MonitoringOut expect(outcome).to.have.property('events').that.is.an('array'); } +/** + * Returns true if any hello response in the test reports a server with a + * maxWireVersion below the driver's minimum supported wire version. + */ +function reliesOnIncompatibleServer(testData: SDAMTest): boolean { + return testData.phases.some( + phase => + 'responses' in phase && + (phase.responses || []).some( + ([, { maxWireVersion }]) => maxWireVersion < MIN_SUPPORTED_WIRE_VERSION + ) + ); +} + describe('Server Discovery and Monitoring (spec)', function () { let serverConnect: sinon.SinonStub; @@ -234,7 +249,10 @@ describe('Server Discovery and Monitoring (spec)', function () { }); for (const testData of specTests[specTestName]) { - it(testData.description, async () => { + it(testData.description, async function () { + if (reliesOnIncompatibleServer(testData)) { + this.skip(); + } await executeSDAMTest(testData); }); } diff --git a/test/unit/cmap/wire_protocol/constants.test.ts b/test/unit/cmap/wire_protocol/constants.test.ts index 1ca468c0c06..662497909fc 100644 --- a/test/unit/cmap/wire_protocol/constants.test.ts +++ b/test/unit/cmap/wire_protocol/constants.test.ts @@ -9,8 +9,8 @@ import { describe('Wire Protocol Constants', function () { describe('MIN_SUPPORTED_SERVER_VERSION', function () { - it('returns 4.2', function () { - expect(MIN_SUPPORTED_SERVER_VERSION).to.equal('4.2'); + it('returns 4.4', function () { + expect(MIN_SUPPORTED_SERVER_VERSION).to.equal('4.4'); }); }); @@ -21,8 +21,8 @@ describe('Wire Protocol Constants', function () { }); describe('MIN_SUPPORTED_WIRE_VERSION', function () { - it('returns 8', function () { - expect(MIN_SUPPORTED_WIRE_VERSION).to.equal(8); + it('returns 9', function () { + expect(MIN_SUPPORTED_WIRE_VERSION).to.equal(9); }); }); diff --git a/test/unit/error.test.ts b/test/unit/error.test.ts index 5315dcdea2d..ca93dfa0e24 100644 --- a/test/unit/error.test.ts +++ b/test/unit/error.test.ts @@ -460,7 +460,6 @@ describe('MongoErrors', () => { // 9 - above server version 4.4 const ABOVE_4_4 = 9; - const BELOW_4_4 = 8; const tests: { description: string; @@ -468,36 +467,6 @@ describe('MongoErrors', () => { error: Error; maxWireVersion: number; }[] = [ - { - description: 'a plain error', - result: false, - error: new Error('do not retry me!'), - maxWireVersion: BELOW_4_4 - }, - { - description: 'a MongoError with no code nor label', - result: false, - error: new MongoError('do not retry me!'), - maxWireVersion: BELOW_4_4 - }, - { - description: 'network error', - result: true, - error: new MongoNetworkError('socket bad, try again'), - maxWireVersion: BELOW_4_4 - }, - { - description: 'a MongoWriteConcernError with a random label', - result: false, - error: new MongoWriteConcernError({ - writeConcernError: { - errmsg: 'random label', - code: 1 - }, - errorLabels: ['myLabel'] - }), - maxWireVersion: BELOW_4_4 - }, { description: 'a MongoWriteConcernError with a retryable code above server 4.4', result: false, @@ -509,29 +478,6 @@ describe('MongoErrors', () => { }), maxWireVersion: ABOVE_4_4 }, - { - description: 'a MongoWriteConcernError with a retryable code below server 4.4', - result: true, - error: new MongoWriteConcernError({ - writeConcernError: { - errmsg: 'code 262', - code: 262 - } - }), - maxWireVersion: BELOW_4_4 - }, - { - description: 'a MongoWriteConcernError with a RetryableWriteError label below server 4.4', - result: false, - error: new MongoWriteConcernError({ - writeConcernError: { - errmsg: 'code 1', - code: 1 - }, - errorLabels: ['RetryableWriteError'] - }), - maxWireVersion: BELOW_4_4 - }, { description: 'a MongoWriteConcernError with a RetryableWriteError label above server 4.4', result: false, @@ -557,9 +503,9 @@ describe('MongoErrors', () => { maxWireVersion: ABOVE_4_4 } ]; - for (const { description, result, error, maxWireVersion } of tests) { + for (const { description, result, error } of tests) { it(`${description} ${result ? 'needs' : 'does not need'} a retryable write label`, () => { - expect(needsRetryableWriteLabel(error, maxWireVersion)).to.be.equal(result); + expect(needsRetryableWriteLabel(error)).to.be.equal(result); }); } }); @@ -626,11 +572,10 @@ describe('MongoErrors', () => { expect(isResumableError(mongoError, 8)).to.be.true; }); - it('for resumable codes if wireVersion is below 9 or unspecified', () => { + it('for resumable codes if wireVersion is unspecified', () => { const mongoError = new MongoError('ah!'); mongoError.code = MONGODB_ERROR_CODES.ShutdownInProgress; // Shutdown in progress is resumable expect(isResumableError(mongoError)).to.be.true; - expect(isResumableError(mongoError, 8)).to.be.true; }); it('for labeled MongoError only if the wireVersion is at least 9', () => { @@ -697,14 +642,6 @@ describe('MongoErrors', () => { expect(isResumableError(mongoError, 8)).to.be.false; expect(isResumableError(mongoError, 9)).to.be.false; }); - - it('for labeled error below wire version 9', () => { - const mongoError = new MongoError('ah!'); - mongoError.addErrorLabel(MongoErrorLabel.ResumableChangeStreamError); - expect(mongoError.hasErrorLabel(MongoErrorLabel.ResumableChangeStreamError)).to.be.true; - expect(isResumableError(mongoError, 8)).to.be.false; - expect(isResumableError(mongoError)).to.be.false; - }); }); }); diff --git a/test/unit/operations/list_collections.test.js b/test/unit/operations/list_collections.test.js index 927f94a725f..e050b7ef581 100644 --- a/test/unit/operations/list_collections.test.js +++ b/test/unit/operations/list_collections.test.js @@ -68,21 +68,6 @@ describe('ListCollectionsOperation', function () { const description = new StreamDescription(); context('when comment is provided', function () { - context('when the wireVersion < 9', function () { - it('does not set a comment on the command', function () { - const operation = new ListCollectionsOperation( - db, - {}, - { dbName: db, comment: 'test comment' } - ); - description.maxWireVersion = 8; - const command = operation.buildCommandDocument({ - description - }); - expect(command).not.to.haveOwnProperty('comment'); - }); - }); - context('when the wireVersion >= 9', function () { it('sets a comment on the command', function () { const operation = new ListCollectionsOperation(