diff --git a/src/change_stream.ts b/src/change_stream.ts index 1e80cf7e58e..9d195583dca 100644 --- a/src/change_stream.ts +++ b/src/change_stream.ts @@ -5,7 +5,8 @@ import { isResumableError, MongoDriverError, MongoAPIError, - MongoChangeStreamError + MongoChangeStreamError, + MongoRuntimeError } from './error'; import { AggregateOperation, AggregateOptions } from './operations/aggregate'; import { @@ -558,8 +559,9 @@ function setIsEmitter(changeStream: ChangeStream): void { function setIsIterator(changeStream: ChangeStream): void { if (changeStream[kMode] === 'emitter') { + // TODO(NODE-3485): Replace with MongoChangeStreamModeError throw new MongoAPIError( - 'ChangeStream cannot be used as an EventEmitter after being used as an iterator' + 'ChangeStream cannot be used as an iterator after being used as an EventEmitter' ); } changeStream[kMode] = 'iterator'; @@ -683,15 +685,15 @@ function processNewChange( callback?: Callback> ) { if (changeStream[kClosed]) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - if (callback) callback(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR)); + // TODO(NODE-3485): Replace with MongoChangeStreamClosedError + if (callback) callback(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR)); return; } // a null change means the cursor has been notified, implicitly closing the change stream if (change == null) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - return closeWithError(changeStream, new MongoDriverError(CHANGESTREAM_CLOSED_ERROR), callback); + // TODO(NODE-3485): Replace with MongoChangeStreamClosedError + return closeWithError(changeStream, new MongoRuntimeError(CHANGESTREAM_CLOSED_ERROR), callback); } if (change && !change._id) { @@ -723,8 +725,8 @@ function processError( // If the change stream has been closed explicitly, do not process error. if (changeStream[kClosed]) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - if (callback) callback(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR)); + // TODO(NODE-3485): Replace with MongoChangeStreamClosedError + if (callback) callback(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR)); return; } @@ -784,8 +786,8 @@ function processError( */ function getCursor(changeStream: ChangeStream, callback: Callback>) { if (changeStream[kClosed]) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - callback(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR)); + // TODO(NODE-3485): Replace with MongoChangeStreamClosedError + callback(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR)); return; } @@ -810,8 +812,8 @@ function processResumeQueue(changeStream: ChangeStream, err?: const request = changeStream[kResumeQueue].pop(); if (!err) { if (changeStream[kClosed]) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - request(new MongoDriverError(CHANGESTREAM_CLOSED_ERROR)); + // TODO(NODE-3485): Replace with MongoChangeStreamClosedError + request(new MongoAPIError(CHANGESTREAM_CLOSED_ERROR)); return; } if (!changeStream.cursor) { diff --git a/src/cmap/commands.ts b/src/cmap/commands.ts index 140fea90cd2..0ee6da3c86f 100644 --- a/src/cmap/commands.ts +++ b/src/cmap/commands.ts @@ -84,7 +84,7 @@ export class Query { // Validate that we are not passing 0x00 in the collection name if (ns.indexOf('\x00') !== -1) { - // TODO(NODE-3483): Replace with MongoCommandError + // TODO(NODE-3483): Use MongoNamespace static method throw new MongoDriverError('Namespace cannot contain a null character'); } diff --git a/src/cmap/connection_pool.ts b/src/cmap/connection_pool.ts index d63c10d8b97..a2c12ca75ad 100644 --- a/src/cmap/connection_pool.ts +++ b/src/cmap/connection_pool.ts @@ -5,7 +5,12 @@ import { Logger } from '../logger'; import { ConnectionPoolMetrics } from './metrics'; import { connect } from './connect'; import { eachAsync, makeCounter, Callback } from '../utils'; -import { MongoDriverError, MongoError, MongoInvalidArgumentError } from '../error'; +import { + MongoError, + MongoInvalidArgumentError, + MongoDriverError, + MongoRuntimeError +} from '../error'; import { PoolClosedError, WaitQueueTimeoutError } from './errors'; import { ConnectionPoolCreatedEvent, @@ -388,7 +393,8 @@ export class ConnectionPool extends TypedEventEmitter { clearTimeout(waitQueueMember.timer); } if (!waitQueueMember[kCancelled]) { - waitQueueMember.callback(new MongoDriverError('connection pool closed')); + // TODO(NODE-3483): Replace with MongoConnectionPoolClosedError + waitQueueMember.callback(new MongoRuntimeError('Connection pool closed')); } } } diff --git a/src/error.ts b/src/error.ts index 2e8c0a5d195..9e90599119a 100644 --- a/src/error.ts +++ b/src/error.ts @@ -226,8 +226,8 @@ export class MongoRuntimeError extends MongoDriverError { * @category Error */ export class MongoBatchReExecutionError extends MongoAPIError { - constructor(message?: string) { - super(message || 'This batch has already been executed, create new batch to execute'); + constructor(message = 'This batch has already been executed, create new batch to execute') { + super(message); } get name(): string { @@ -294,7 +294,7 @@ export class MongoTransactionError extends MongoAPIError { * @category Error */ export class MongoExpiredSessionError extends MongoAPIError { - constructor(message: string) { + constructor(message = 'Cannot use a session that has ended') { super(message); } @@ -343,8 +343,8 @@ export class MongoChangeStreamError extends MongoRuntimeError { * @category Error */ export class MongoTailableCursorError extends MongoAPIError { - constructor(message?: string) { - super(message || 'Tailable cursor does not support this operation'); + constructor(message = 'Tailable cursor does not support this operation') { + super(message); } get name(): string { @@ -392,8 +392,8 @@ export class MongoGridFSChunkError extends MongoRuntimeError { * @category Error */ export class MongoCursorInUseError extends MongoAPIError { - constructor(message?: string) { - super(message || 'Cursor is already initialized'); + constructor(message = 'Cursor is already initialized') { + super(message); } get name(): string { @@ -409,7 +409,7 @@ export class MongoCursorInUseError extends MongoAPIError { * @category Error */ export class MongoServerClosedError extends MongoAPIError { - constructor(message: string) { + constructor(message = 'Server is closed') { super(message); } @@ -442,7 +442,7 @@ export class MongoCursorExhaustedError extends MongoAPIError { * @category Error */ export class MongoTopologyClosedError extends MongoAPIError { - constructor(message: string) { + constructor(message = 'Topology is closed') { super(message); } diff --git a/src/gridfs/upload.ts b/src/gridfs/upload.ts index ff52e526633..5f3cad54d6b 100644 --- a/src/gridfs/upload.ts +++ b/src/gridfs/upload.ts @@ -2,15 +2,8 @@ import { Writable } from 'stream'; import type { Document } from '../bson'; import { ObjectId } from '../bson'; import type { Collection } from '../collection'; -import { - AnyError, - MONGODB_ERROR_CODES, - MongoDriverError, - MongoError, - MongoGridFSStreamError -} from '../error'; -import { PromiseProvider } from '../promise_provider'; -import type { Callback } from '../utils'; +import { AnyError, MONGODB_ERROR_CODES, MongoError, MongoAPIError } from '../error'; +import { Callback, maybePromise } from '../utils'; import type { WriteConcernOptions } from '../write_concern'; import { WriteConcern } from './../write_concern'; import type { GridFSFile } from './download'; @@ -149,27 +142,19 @@ export class GridFSBucketWriteStream extends Writable { abort(): Promise; abort(callback: Callback): void; abort(callback?: Callback): Promise | void { - const Promise = PromiseProvider.get(); - let error: MongoGridFSStreamError; - if (this.state.streamEnd) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - error = new MongoDriverError('Cannot abort a stream that has already completed'); - if (typeof callback === 'function') { - return callback(error); + return maybePromise(callback, callback => { + if (this.state.streamEnd) { + // TODO(NODE-3485): Replace with MongoGridFSStreamClosed + return callback(new MongoAPIError('Cannot abort a stream that has already completed')); } - return Promise.reject(error); - } - if (this.state.aborted) { - // TODO(NODE-3405): Replace with MongoStreamClosedError - error = new MongoDriverError('Cannot call abort() on a stream twice'); - if (typeof callback === 'function') { - return callback(error); + + if (this.state.aborted) { + // TODO(NODE-3485): Replace with MongoGridFSStreamClosed + return callback(new MongoAPIError('Cannot call abort() on a stream twice')); } - return Promise.reject(error); - } - this.state.aborted = true; - this.chunks.deleteMany({ files_id: this.id }, error => { - if (typeof callback === 'function') callback(error); + + this.state.aborted = true; + this.chunks.deleteMany({ files_id: this.id }, error => callback(error)); }); } @@ -565,8 +550,8 @@ function writeRemnant(stream: GridFSBucketWriteStream, callback?: Callback): boo function checkAborted(stream: GridFSBucketWriteStream, callback?: Callback): boolean { if (stream.state.aborted) { if (typeof callback === 'function') { - // TODO(NODE-3405): Replace with MongoStreamClosedError - callback(new MongoDriverError('this stream has been aborted')); + // TODO(NODE-3485): Replace with MongoGridFSStreamClosedError + callback(new MongoAPIError('Stream has been aborted')); } return true; } diff --git a/src/index.ts b/src/index.ts index f58caa191ca..b06f4ac0ea1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -52,7 +52,12 @@ export { MongoBatchReExecutionError, MongoCursorExhaustedError, MongoCursorInUseError, - MongoNotConnectedError + MongoNotConnectedError, + MongoExpiredSessionError, + MongoTransactionError, + MongoKerberosError, + MongoServerClosedError, + MongoTopologyClosedError } from './error'; export { MongoBulkWriteError, BulkWriteOptions, AnyBulkWriteOperation } from './bulk/common'; export { diff --git a/src/operations/common_functions.ts b/src/operations/common_functions.ts index 2ac555bfd43..f056f32a64a 100644 --- a/src/operations/common_functions.ts +++ b/src/operations/common_functions.ts @@ -1,4 +1,4 @@ -import { MongoDriverError } from '../error'; +import { MongoTopologyClosedError } from '../error'; import { Callback, getTopology } from '../utils'; import type { Document } from '../bson'; import type { Db } from '../db'; @@ -41,8 +41,7 @@ export function indexInformation( const full = options.full == null ? false : options.full; // Did the user destroy the topology - if (getTopology(db).isDestroyed()) - return callback(new MongoDriverError('topology was destroyed')); + if (getTopology(db).isDestroyed()) return callback(new MongoTopologyClosedError()); // Process all the results from the index command and collection function processResults(indexes: any) { // Contains all the information diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index 48591a68b0d..2777565c4a9 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -6,7 +6,9 @@ import { MongoDriverError, MongoNetworkError, MongoCompatibilityError, - MongoServerError + MongoServerError, + MongoExpiredSessionError, + MongoTransactionError } from '../error'; import { Aspect, AbstractOperation } from './operation'; import { maxWireVersion, maybePromise, Callback } from '../utils'; @@ -88,10 +90,9 @@ export function executeOperation< owner = Symbol(); session = topology.startSession({ owner, explicit: false }); } else if (session.hasEnded) { - // TODO(NODE-3405): Change this out for MongoExpiredSessionError - return cb(new MongoDriverError('Use of expired sessions is not permitted')); + return cb(new MongoExpiredSessionError('Use of expired sessions is not permitted')); } else if (session.snapshotEnabled && !topology.capabilities.supportsSnapshotReads) { - return cb(new MongoDriverError('Snapshot reads require MongoDB 5.0 or later')); + return cb(new MongoCompatibilityError('Snapshot reads require MongoDB 5.0 or later')); } } else if (session) { // If the user passed an explicit session and we are still, after server selection, @@ -132,8 +133,7 @@ function executeWithServerSelection( if (inTransaction && !readPreference.equals(ReadPreference.primary)) { callback( - // TODO(NODE-3405): Change this out for MongoTransactionError - new MongoDriverError( + new MongoTransactionError( `Read preference in a transaction must be primary, not: ${readPreference.mode}` ) ); @@ -218,8 +218,7 @@ function executeWithServerSelection( session.inTransaction() ) { callback( - // TODO(NODE-3405): Change this out for MongoTransactionError - new MongoDriverError( + new MongoTransactionError( `Read preference in a transaction must be primary, not: ${readPreference.mode}` ) ); diff --git a/src/sdam/server.ts b/src/sdam/server.ts index 3900483aebd..e3f1fb40965 100644 --- a/src/sdam/server.ts +++ b/src/sdam/server.ts @@ -33,9 +33,9 @@ import { isRetryableWriteError, isNodeShuttingDownError, isNetworkErrorBeforeHandshake, - MongoDriverError, MongoCompatibilityError, - MongoInvalidArgumentError + MongoInvalidArgumentError, + MongoServerClosedError } from '../error'; import { Connection, @@ -292,8 +292,7 @@ export class Server extends TypedEventEmitter { } if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) { - // TODO(NODE-3405): Change this out for MongoServerClosedError - callback(new MongoDriverError('Server is closed')); + callback(new MongoServerClosedError()); return; } @@ -351,7 +350,7 @@ export class Server extends TypedEventEmitter { */ query(ns: MongoDBNamespace, cmd: Document, options: QueryOptions, callback: Callback): void { if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) { - callback(new MongoDriverError('server is closed')); + callback(new MongoServerClosedError()); return; } @@ -385,7 +384,7 @@ export class Server extends TypedEventEmitter { callback: Callback ): void { if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) { - callback(new MongoDriverError('server is closed')); + callback(new MongoServerClosedError()); return; } @@ -420,7 +419,7 @@ export class Server extends TypedEventEmitter { ): void { if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) { if (typeof callback === 'function') { - callback(new MongoDriverError('server is closed')); + callback(new MongoServerClosedError()); } return; diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index 48ee8e4f5df..8edc47a7f8e 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -11,7 +11,12 @@ import { } from '../sessions'; import { SrvPoller, SrvPollingEvent } from './srv_polling'; import { CMAP_EVENTS, ConnectionPoolEvents } from '../cmap/connection_pool'; -import { MongoServerSelectionError, MongoCompatibilityError, MongoDriverError } from '../error'; +import { + MongoServerSelectionError, + MongoCompatibilityError, + MongoDriverError, + MongoTopologyClosedError +} from '../error'; import { readPreferenceServerSelector, ServerSelector } from './server_selection'; import { makeStateMachine, @@ -491,7 +496,7 @@ export class Topology extends TypedEventEmitter { stateTransition(this, STATE_CLOSING); - drainWaitQueue(this[kWaitQueue], new MongoDriverError('Topology closed')); + drainWaitQueue(this[kWaitQueue], new MongoTopologyClosedError()); drainTimerQueue(this.s.connectionTimers); if (this.s.srvPoller) { @@ -979,10 +984,7 @@ function drainWaitQueue(queue: Denque, err?: MongoDriver function processWaitQueue(topology: Topology) { if (topology.s.state === STATE_CLOSED) { - drainWaitQueue( - topology[kWaitQueue], - new MongoDriverError('Topology is closed, please connect') - ); + drainWaitQueue(topology[kWaitQueue], new MongoTopologyClosedError()); return; } diff --git a/src/sessions.ts b/src/sessions.ts index a7a4428d5d7..0d6483a795b 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -14,7 +14,10 @@ import { MONGODB_ERROR_CODES, MongoDriverError, MongoServerError, - AnyError + AnyError, + MongoExpiredSessionError, + MongoTransactionError, + MongoRuntimeError } from './error'; import { now, @@ -41,7 +44,7 @@ const minWireVersionForShardedTransactions = 8; function assertAlive(session: ClientSession, callback?: Callback): boolean { if (session.serverSession == null) { - const error = new MongoDriverError('Cannot use a session that has ended'); + const error = new MongoExpiredSessionError(); if (typeof callback === 'function') { callback(error); return false; @@ -370,12 +373,12 @@ export class ClientSession extends TypedEventEmitter { */ startTransaction(options?: TransactionOptions): void { if (this[kSnapshotEnabled]) { - throw new MongoDriverError('Transactions are not allowed with snapshot sessions'); + throw new MongoCompatibilityError('Transactions are not allowed with snapshot sessions'); } assertAlive(this); if (this.inTransaction()) { - throw new MongoDriverError('Transaction already in progress'); + throw new MongoTransactionError('Transaction already in progress'); } if (this.isPinned && this.transaction.isCommitted) { @@ -441,7 +444,7 @@ export class ClientSession extends TypedEventEmitter { * This is here to ensure that ClientSession is never serialized to BSON. */ toBSON(): never { - throw new MongoDriverError('ClientSession cannot be serialized to BSON.'); + throw new MongoRuntimeError('ClientSession cannot be serialized to BSON.'); } /** @@ -643,7 +646,7 @@ function endTransaction(session: ClientSession, commandName: string, callback: C const txnState = session.transaction.state; if (txnState === TxnState.NO_TRANSACTION) { - callback(new MongoDriverError('No transaction started')); + callback(new MongoTransactionError('No transaction started')); return; } @@ -660,7 +663,7 @@ function endTransaction(session: ClientSession, commandName: string, callback: C if (txnState === TxnState.TRANSACTION_ABORTED) { callback( - new MongoDriverError('Cannot call commitTransaction after calling abortTransaction') + new MongoTransactionError('Cannot call commitTransaction after calling abortTransaction') ); return; } @@ -673,7 +676,7 @@ function endTransaction(session: ClientSession, commandName: string, callback: C } if (txnState === TxnState.TRANSACTION_ABORTED) { - callback(new MongoDriverError('Cannot call abortTransaction twice')); + callback(new MongoTransactionError('Cannot call abortTransaction twice')); return; } @@ -682,7 +685,7 @@ function endTransaction(session: ClientSession, commandName: string, callback: C txnState === TxnState.TRANSACTION_COMMITTED_EMPTY ) { callback( - new MongoDriverError('Cannot call abortTransaction after calling commitTransaction') + new MongoTransactionError('Cannot call abortTransaction after calling commitTransaction') ); return; } @@ -957,7 +960,7 @@ export function applySession( ): MongoDriverError | undefined { // TODO: merge this with `assertAlive`, did not want to throw a try/catch here if (session.hasEnded) { - return new MongoDriverError('Attempted to use a session that has ended'); + return new MongoExpiredSessionError(); } const serverSession = session.serverSession; diff --git a/src/transactions.ts b/src/transactions.ts index 4802e6d3bd3..9ab9fa0ea20 100644 --- a/src/transactions.ts +++ b/src/transactions.ts @@ -1,5 +1,5 @@ import { ReadPreference } from './read_preference'; -import { MongoDriverError } from './error'; +import { MongoDriverError, MongoTransactionError } from './error'; import { ReadConcern } from './read_concern'; import { WriteConcern } from './write_concern'; import type { Server } from './sdam/server'; @@ -94,7 +94,7 @@ export class Transaction { const writeConcern = WriteConcern.fromOptions(options); if (writeConcern) { if (writeConcern.w === 0) { - throw new MongoDriverError('Transactions do not support unacknowledged write concern'); + throw new MongoTransactionError('Transactions do not support unacknowledged write concern'); } this.options.writeConcern = writeConcern; diff --git a/src/utils.ts b/src/utils.ts index f6b28a4ff10..cd3c6fa43ca 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -7,7 +7,8 @@ import { MongoDriverError, MongoCompatibilityError, MongoNotConnectedError, - MongoInvalidArgumentError + MongoInvalidArgumentError, + MongoExpiredSessionError } from './error'; import { WriteConcern, WriteConcernOptions, W } from './write_concern'; import type { Server } from './sdam/server'; @@ -74,15 +75,18 @@ export function checkCollectionName(collectionName: string): void { collectionName.indexOf('$') !== -1 && collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null ) { + // TODO(NODE-3483): Use MongoNamespace static method throw new MongoInvalidArgumentError("Collection names must not contain '$'"); } if (collectionName.match(/^\.|\.$/) != null) { + // TODO(NODE-3483): Use MongoNamespace static method throw new MongoInvalidArgumentError("Collection names must not start or end with '.'"); } // Validate that we are not passing 0x00 in the collection name if (collectionName.indexOf('\x00') !== -1) { + // TODO(NODE-3483): Use MongoNamespace static method throw new MongoInvalidArgumentError('Collection names cannot contain a null character'); } } @@ -258,8 +262,7 @@ export function executeLegacyOperation( const optionsIndex = args.length - 2; args[optionsIndex] = Object.assign({}, args[optionsIndex], { session: session }); } else if (opOptions.session && opOptions.session.hasEnded) { - // TODO(NODE-3405): Replace this with MongoExpiredSessionError - throw new MongoDriverError('Use of expired sessions is not permitted'); + throw new MongoExpiredSessionError(); } } diff --git a/test/functional/gridfs_stream.test.js b/test/functional/gridfs_stream.test.js index bfe6a5ec8fc..e23970e3c22 100644 --- a/test/functional/gridfs_stream.test.js +++ b/test/functional/gridfs_stream.test.js @@ -463,18 +463,14 @@ describe('GridFS Stream', function () { expect(error).to.not.exist; expect(c).to.equal(0); uploadStream.write('b', 'utf8', function (error) { - expect(error.toString()).to.equal( - 'MongoDriverError: this stream has been aborted' - ); + expect(error.toString()).to.equal('MongoAPIError: Stream has been aborted'); uploadStream.end('c', 'utf8', function (error) { - expect(error.toString()).to.equal( - 'MongoDriverError: this stream has been aborted' - ); + expect(error.toString()).to.equal('MongoAPIError: Stream has been aborted'); // Fail if user tries to abort an aborted stream uploadStream.abort().then(null, function (error) { expect(error.toString()).to.equal( - // TODO(NODE-3405): Replace with MongoStreamClosedError - 'MongoDriverError: Cannot call abort() on a stream twice' + // TODO(NODE-3485): Replace with MongoGridFSStreamClosedError + 'MongoAPIError: Cannot call abort() on a stream twice' ); client.close(done); }); @@ -517,18 +513,14 @@ describe('GridFS Stream', function () { expect(error).to.not.exist; expect(c).to.equal(0); uploadStream.write('b', 'utf8', function (error) { - expect(error.toString()).to.equal( - 'MongoDriverError: this stream has been aborted' - ); + expect(error.toString()).to.equal('MongoAPIError: Stream has been aborted'); uploadStream.end('c', 'utf8', function (error) { - expect(error.toString()).to.equal( - 'MongoDriverError: this stream has been aborted' - ); + expect(error.toString()).to.equal('MongoAPIError: Stream has been aborted'); // Fail if user tries to abort an aborted stream uploadStream.abort().then(null, function (error) { expect(error.toString()).to.equal( - // TODO(NODE-3405): Replace with MongoStreamClosedError - 'MongoDriverError: Cannot call abort() on a stream twice' + // TODO(NODE-3485): Replace with MongoGridFSStreamClosedError + 'MongoAPIError: Cannot call abort() on a stream twice' ); client.close(done); }); @@ -1174,20 +1166,16 @@ describe('GridFS Stream', function () { expect(c).to.equal(0); uploadStream.write('b', 'utf8', function (error) { - expect(error.toString()).to.equal( - 'MongoDriverError: this stream has been aborted' - ); + expect(error.toString()).to.equal('MongoAPIError: Stream has been aborted'); uploadStream.end(function (error) { - expect(error.toString()).to.equal( - 'MongoDriverError: this stream has been aborted' - ); + expect(error.toString()).to.equal('MongoAPIError: Stream has been aborted'); // Fail if user tries to abort an aborted stream uploadStream.abort().then(null, function (error) { expect(error.toString()).to.equal( - // TODO(NODE-3405): Replace with MongoStreamClosedError - 'MongoDriverError: Cannot call abort() on a stream twice' + // TODO(NODE-3485): Replace with MongoGridFSStreamClosedError + 'MongoAPIError: Cannot call abort() on a stream twice' ); client.close(done); });