Skip to content

Commit 15dc8ee

Browse files
added more prose tests
1 parent ad151f7 commit 15dc8ee

File tree

5 files changed

+176
-87
lines changed

5 files changed

+176
-87
lines changed

src/utils.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,14 +1141,21 @@ export function matchesParentDomain(address: string, srvHost: string): boolean {
11411141
const normalizedSrvHost = srvHost.endsWith('.') ? srvHost.slice(0, srvHost.length - 1) : srvHost;
11421142

11431143
const allCharacterBeforeFirstDot = /^.*?\./;
1144+
const srvIsLessThanThreeParts = srvHost.split('.').length < 3;
11441145
// Remove all characters before first dot
11451146
// Add leading dot back to string so
11461147
// an srvHostDomain = '.trusted.site'
11471148
// will not satisfy an addressDomain that endsWith '.fake-trusted.site'
11481149
const addressDomain = `.${normalizedAddress.replace(allCharacterBeforeFirstDot, '')}`;
1149-
const srvHostDomain = `.${normalizedSrvHost.replace(allCharacterBeforeFirstDot, '')}`;
1150+
const srvHostDomain = srvIsLessThanThreeParts
1151+
? normalizedSrvHost
1152+
: `.${normalizedSrvHost.replace(allCharacterBeforeFirstDot, '')}`;
11501153

1151-
return addressDomain.endsWith(srvHostDomain);
1154+
return (
1155+
addressDomain.endsWith(srvHostDomain) &&
1156+
(!srvIsLessThanThreeParts ||
1157+
normalizedAddress.split('.').length > normalizedSrvHost.split('.').length)
1158+
);
11521159
}
11531160

11541161
interface RequestOptions {

test/integration/change-streams/change_stream.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { strict as assert } from 'assert';
22
import { expect } from 'chai';
3-
import * as dns from 'dns';
43
import { on, once } from 'events';
54
import { gte, lt } from 'semver';
65
import * as sinon from 'sinon';

test/integration/connection-monitoring-and-pooling/connection_pool.test.ts

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import { once } from 'node:events';
33
import { expect } from 'chai';
44

55
import { type ConnectionPoolCreatedEvent, type Db, type MongoClient } from '../../mongodb';
6-
import sinon = require('sinon');
7-
import dns = require('dns');
86

97
describe('Connection Pool', function () {
108
let client: MongoClient;
@@ -21,52 +19,6 @@ describe('Connection Pool', function () {
2119

2220
describe('Events', function () {
2321
describe('ConnectionPoolCreatedEvent', function () {
24-
describe.only(
25-
'Initial DNS Seedlist Discovery (Prose Tests)',
26-
{ requires: { topology: 'single' } },
27-
() => {
28-
function makeSrvStub() {
29-
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
30-
return [
31-
{
32-
name: 'localhost',
33-
port: 27017,
34-
weight: 0,
35-
priority: 0
36-
}
37-
];
38-
});
39-
40-
sinon.stub(dns.promises, 'resolveTxt').callsFake(async () => {
41-
throw { code: 'ENODATA' };
42-
});
43-
}
44-
45-
afterEach(async function () {
46-
sinon.restore();
47-
});
48-
49-
it('1.1 Driver should not throw error on valid SRV URI with one part', async function () {
50-
// 1. make dns resolution always pass
51-
makeSrvStub();
52-
// 2. assert that creating a MongoClient with the uri 'mongodb+srv:/localhost' does not cause an error
53-
client = this.configuration.newClient('mongodb+srv://localhost', {});
54-
console.log('stubbed srv client', client);
55-
// 3. assert that connecting the client from 2. to the server does not cause an error
56-
//await client.connect();
57-
});
58-
59-
it('1.1 Driver should not throw error on valid SRV URI with two parts', async function () {
60-
// 1. make dns resolution always pass
61-
makeSrvStub();
62-
// 2. assert that creating a MongoClient with the uri 'mongodb+srv://mongodb.localhost' does not cause an error
63-
const client = this.configuration.newClient('mongodb://localhost', {});
64-
console.log('stubbed normal client', client);
65-
// 3. assert that connecting the client to the server does not cause an error
66-
//await client.connect();
67-
});
68-
}
69-
);
7022
context('when no connection pool options are passed in', function () {
7123
let pConnectionPoolCreated: Promise<ConnectionPoolCreatedEvent[]>;
7224
let connectionPoolCreated: ConnectionPoolCreatedEvent;

test/integration/crud/bulk.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ describe('Bulk', function () {
723723
}
724724
});
725725

726-
it.only(
726+
it(
727727
'should correctly execute ordered batch using w:0',
728728
// TODO(NODE-6060): set `moreToCome` op_msg bit when `w: 0` is specified
729729
{ requires: { mongodb: '<8.0.0' } },
Lines changed: 166 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,183 @@
11
import * as dns from 'dns';
22
import sinon = require('sinon');
3-
// import { expect } from 'chai';
43

5-
import { type MongoClient } from '../../mongodb';
4+
import { expect } from 'chai';
5+
6+
import { MongoAPIError, Server, ServerDescription, Topology } from '../../mongodb';
7+
import { topologyWithPlaceholderClient } from '../../tools/utils';
68

79
describe(
810
'Initial DNS Seedlist Discovery (Prose Tests)',
911
{ requires: { topology: 'single' } },
1012
() => {
11-
let client: MongoClient;
12-
13-
function makeSrvStub() {
14-
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
15-
return [
16-
{
17-
name: 'localhost',
18-
port: 27017,
19-
weight: 0,
20-
priority: 0
21-
}
22-
];
13+
context('When running validation on an SRV string before DNS resolution', function () {
14+
beforeEach(async function () {
15+
// this fn stubs DNS resolution to always pass - so we are only checking pre-DNS validation
16+
17+
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
18+
return [
19+
{
20+
name: 'resolved.mongodb.localhost',
21+
port: 27017,
22+
weight: 0,
23+
priority: 0
24+
}
25+
];
26+
});
27+
28+
sinon.stub(dns.promises, 'resolveTxt').callsFake(async () => {
29+
throw { code: 'ENODATA' };
30+
});
31+
32+
sinon.stub(Topology.prototype, 'selectServer').callsFake(async () => {
33+
return new Server(
34+
topologyWithPlaceholderClient([], {} as any),
35+
new ServerDescription('a:1'),
36+
{} as any
37+
);
38+
});
2339
});
2440

25-
sinon.stub(dns.promises, 'resolveTxt').callsFake(async () => {
26-
throw { code: 'ENODATA' };
41+
afterEach(async function () {
42+
sinon.restore();
2743
});
28-
}
2944

30-
afterEach(async function () {
31-
sinon.restore();
32-
});
45+
it('do not error on an SRV because it has one domain level', async function () {
46+
const client = await this.configuration.newClient('mongodb+srv://localhost', {});
47+
client.connect();
48+
client.close();
49+
});
3350

34-
it('1.1 Driver should not throw error on valid SRV URI with one part', async function () {
35-
// 1. make dns resolution always pass
36-
//makeSrvStub();
37-
// 2. assert that creating a MongoClient with the uri 'mongodb+srv:/localhost' does not cause an error
38-
client = this.configuration.newClient('mongodb://localhost', {});
39-
// 3. assert that connecting the client from 2. to the server does not cause an error
40-
await client.connect();
51+
it('do not error on an SRV because it has two domain levels', async function () {
52+
const client = await this.configuration.newClient('mongodb+srv://mongodb.localhost', {});
53+
client.connect();
54+
client.close();
55+
});
4156
});
4257

43-
it('1.1 Driver should not throw error on valid SRV URI with two parts', async function () {
44-
// 1. make dns resolution always pass
45-
makeSrvStub();
46-
// 2. assert that creating a MongoClient with the uri 'mongodb+srv://mongodb.localhost' does not cause an error
47-
//const client = new MongoClient('mongodb+srv://mongodb.localhost', {});
48-
// 3. assert that connecting the client to the server does not cause an error
49-
//await client.connect();
50-
});
58+
context(
59+
'When given a DNS resolution that does NOT end with the original SRVs domain name',
60+
function () {
61+
beforeEach(async function () {
62+
sinon.stub(dns.promises, 'resolveTxt').callsFake(async () => {
63+
throw { code: 'ENODATA' };
64+
});
65+
});
66+
67+
afterEach(async function () {
68+
sinon.restore();
69+
});
70+
71+
it('an SRV with one domain level causes a runtime error', async function () {
72+
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
73+
return [
74+
{
75+
name: 'localhost.mongodb', // this string contains the SRV but does not end with it
76+
port: 27017,
77+
weight: 0,
78+
priority: 0
79+
}
80+
];
81+
});
82+
const err = await this.configuration
83+
.newClient('mongodb+srv://localhost', {})
84+
.connect()
85+
.catch(e => e);
86+
expect(err).to.be.instanceOf(MongoAPIError);
87+
expect(err.message).to.equal('Server record does not share hostname with parent URI');
88+
});
89+
90+
it('an SRV with two domain levels causes a runtime error', async function () {
91+
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
92+
return [
93+
{
94+
name: 'evil.localhost', // this string only ends with part of the domain, not all of it!
95+
port: 27017,
96+
weight: 0,
97+
priority: 0
98+
}
99+
];
100+
});
101+
const err = await this.configuration
102+
.newClient('mongodb+srv://mongodb.localhost', {})
103+
.connect()
104+
.catch(e => e);
105+
expect(err).to.be.instanceOf(MongoAPIError);
106+
expect(err.message).to.equal('Server record does not share hostname with parent URI');
107+
});
108+
109+
it('an SRV with three or more domain levels causes a runtime error', async function () {
110+
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
111+
return [
112+
{
113+
name: 'blogs.evil.co.uk',
114+
port: 27017,
115+
weight: 0,
116+
priority: 0
117+
}
118+
];
119+
});
120+
const err = await this.configuration
121+
.newClient('mongodb+srv://blogs.mongodb.com', {})
122+
.connect()
123+
.catch(e => e);
124+
expect(err).to.be.instanceOf(MongoAPIError);
125+
expect(err.message).to.equal('Server record does not share hostname with parent URI');
126+
});
127+
}
128+
);
129+
130+
context(
131+
'When given a DNS resolution that is identical to the original SRVs hostname',
132+
function () {
133+
beforeEach(async function () {
134+
sinon.stub(dns.promises, 'resolveTxt').callsFake(async () => {
135+
throw { code: 'ENODATA' };
136+
});
137+
});
138+
139+
afterEach(async function () {
140+
sinon.restore();
141+
});
142+
143+
it('an SRV with one domain level causes a runtime error', async function () {
144+
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
145+
return [
146+
{
147+
name: 'localhost', // this string contains the SRV but does not end with it
148+
port: 27017,
149+
weight: 0,
150+
priority: 0
151+
}
152+
];
153+
});
154+
const err = await this.configuration
155+
.newClient('mongodb+srv://localhost', {})
156+
.connect()
157+
.catch(e => e);
158+
expect(err).to.be.instanceOf(MongoAPIError);
159+
expect(err.message).to.equal('Server record does not share hostname with parent URI');
160+
});
161+
162+
it('an SRV with two domain levels causes a runtime error', async function () {
163+
sinon.stub(dns.promises, 'resolveSrv').callsFake(async () => {
164+
return [
165+
{
166+
name: 'mongodb.localhost', // this string only ends with part of the domain, not all of it!
167+
port: 27017,
168+
weight: 0,
169+
priority: 0
170+
}
171+
];
172+
});
173+
const err = await this.configuration
174+
.newClient('mongodb+srv://mongodb.localhost', {})
175+
.connect()
176+
.catch(e => e);
177+
expect(err).to.be.instanceOf(MongoAPIError);
178+
expect(err.message).to.equal('Server record does not share hostname with parent URI');
179+
});
180+
}
181+
);
51182
}
52183
);

0 commit comments

Comments
 (0)