Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/cmap/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,14 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
}
}

if (this.socket.write(buffer)) return;
try {
if (this.socket.write(buffer)) return;
} catch (writeError) {
const cause = writeError as Error;
const networkError = new MongoNetworkError(cause.message, { cause });
this.onError(networkError);
throw networkError;
}

const drainEvent = once<void>(this.socket, 'drain', options);
const timeout = options?.timeoutContext?.timeoutForSocketWrite;
Expand Down
47 changes: 45 additions & 2 deletions test/integration/node-specific/convert_socket_errors.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Duplex } from 'node:stream';
import { expect } from 'chai';
import * as sinon from 'sinon';

import { type MongoClient, MongoNetworkError } from '../../../src';
import { type Collection, type Document, type MongoClient, MongoNetworkError } from '../../../src';
import { Connection } from '../../../src/cmap/connection';
import { ns } from '../../../src/utils';
import { clearFailPoint, configureFailPoint } from '../../tools/utils';
Expand Down Expand Up @@ -41,7 +41,7 @@ describe('Socket Errors', () => {

describe('when destroyed by failpoint', () => {
let client: MongoClient;
let collection;
let collection: Collection<Document>;

const metadata: MongoDBMetadataUI = { requires: { mongodb: '>=4.4' } };

Expand Down Expand Up @@ -77,4 +77,47 @@ describe('Socket Errors', () => {
expect(error, error.stack).to.be.instanceOf(MongoNetworkError);
});
});

describe('when encountering connection error', () => {
let client: MongoClient;
let collection: Collection<Document>;

const metadata: MongoDBMetadataUI = { requires: { mongodb: '>=4.4' } };

beforeEach(async function () {
if (!this.configuration.filters.NodeVersionFilter.filter({ metadata })) {
return;
}

client = this.configuration.newClient({});
await client.connect();
const db = client.db('closeConn');
collection = db.collection('closeConn');
const docs = Array.from({ length: 128 }).map((_, index) => ({ foo: index, bar: 1 }));
await collection.deleteMany({});
await collection.insertMany(docs);

for (const [, server] of client.topology.s.servers) {
//@ts-expect-error: private property
for (const connection of server.pool.connections) {
//@ts-expect-error: private property
const socket = connection.socket;
sinon.stub(socket, 'write').callsFake(function () {
throw new Error('This socket has been ended by the other party');
});
}
}
});

afterEach(async function () {
sinon.restore();
await client.close();
});

it('throws a MongoNetworkError and retries', metadata, async () => {
const item = await collection.findOne({});
expect(item).to.exist;
console.log(item);
});
});
});