Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(NODE-5530): make topology descriptions JSON stringifiable #4070

Merged
merged 6 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
12 changes: 11 additions & 1 deletion src/sdam/topology_description.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ObjectId } from '../bson';
import { EJSON, type ObjectId } from '../bson';
import * as WIRE_CONSTANTS from '../cmap/wire_protocol/constants';
import { type MongoError, MongoRuntimeError } from '../error';
import { compareObjectId, shuffle } from '../utils';
Expand Down Expand Up @@ -342,6 +342,16 @@ export class TopologyDescription {
hasServer(address: string): boolean {
return this.servers.has(address);
}

/**
* Returns a JSON-serializable representation of the TopologyDescription. This is primarily
* intended for use with JSON.stringify().
*
* This method will not throw.
*/
toJSON() {
return EJSON.serialize(this);
aditi-khare-mongoDB marked this conversation as resolved.
Show resolved Hide resolved
}
}

function topologyTypeForServerType(serverType: ServerType): TopologyType {
Expand Down
35 changes: 34 additions & 1 deletion test/integration/node-specific/errors.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect } from 'chai';

import { MongoClient, MongoServerSelectionError } from '../../mongodb';
import { MongoClient, MongoServerSelectionError, ReadPreference } from '../../mongodb';

describe('Error (Integration)', function () {
it('NODE-5296: handles aggregate errors from dns lookup', async function () {
Expand All @@ -10,4 +10,37 @@ describe('Error (Integration)', function () {
expect(error).to.be.instanceOf(MongoServerSelectionError);
expect(error.message).not.to.be.empty;
});

context('when a server selection error is stringified', function () {
it(
'the error"s topology description correctly displays the `servers`',
{ requires: { topology: 'replicaset' } },
async function () {
const client: MongoClient = this.configuration.newClient({
serverSelectionTimeoutMS: 1000
});
try {
await client.connect();

const error = await client
.db('foo')
.collection('bar')
.find(
{},
{
// Use meaningless read preference tags to ensure that the server selection fails
readPreference: new ReadPreference('secondary', [{ ny: 'ny' }])
}
)
.toArray()
.catch(e => JSON.parse(JSON.stringify(e)));

const servers = error.reason.servers;
expect(Object.keys(servers).length > 0).to.be.true;
} finally {
await client.close();
}
}
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,22 @@ describe('TopologyDescription (integration tests)', function () {
await client.close();
});

beforeEach(async function () {
client = this.configuration.newClient();
aditi-khare-mongoDB marked this conversation as resolved.
Show resolved Hide resolved
await client.connect();
});

context('options', function () {
let client: MongoClient;

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

beforeEach(async function () {
client = this.configuration.newClient();
});

context('localThresholdMS', function () {
it('should default to 15ms', async function () {
const options: MongoClientOptions = {};
Expand All @@ -35,15 +50,6 @@ describe('TopologyDescription (integration tests)', function () {
});

context('topology types', function () {
let client: MongoClient;
beforeEach(async function () {
client = this.configuration.newClient();
});

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

const topologyTypesMap = new Map<TopologyTypeRequirement, TopologyType>([
['single', TopologyType.Single],
['replicaset', TopologyType.ReplicaSetWithPrimary],
Expand All @@ -65,4 +71,23 @@ describe('TopologyDescription (integration tests)', function () {
);
}
});

describe('json stringification', function () {
it('can be stringified without error', function () {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
const description = client.topology?.description!;
expect(description).to.exist;

expect(() => JSON.stringify(description)).not.to.throw;
});

it('properly stringifies the server description map', function () {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-non-null-asserted-optional-chain
const description = client.topology?.description!;
expect(description).to.exist;

const { servers } = JSON.parse(JSON.stringify(description));
expect(Object.keys(servers).length > 0, '`servers` stringified with no servers.').to.be.true;
});
});
});
Loading