Skip to content

Commit 3412bb1

Browse files
boilerplate execution
1 parent 8adca00 commit 3412bb1

File tree

6 files changed

+174
-36
lines changed

6 files changed

+174
-36
lines changed

no_resource_leak_connect_close.cjs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict';
2+
3+
/* eslint-disable no-undef */
4+
5+
const driverPath = "/Users/aditi.khare/Desktop/node-mongodb-native/lib";
6+
const func = (async function run({ MongoClient, uri }) {
7+
const mongoClient = new MongoClient(uri, { minPoolSize: 100 });
8+
await mongoClient.connect();
9+
// Any operations will reproduce the issue found in v5.0.0/v4.13.0
10+
// it would seem the MessageStream has to be used?
11+
await mongoClient.db().command({ ping: 1 });
12+
await mongoClient.close();
13+
});
14+
const name = "no_resource_leak_connect_close";
15+
const uri = "mongodb://bob:pwd123@localhost:31000/integration_tests?replicaSet=rs&authSource=admin";
16+
const iterations = 100;
17+
18+
const { MongoClient } = require(driverPath);
19+
const process = require('node:process');
20+
const v8 = require('node:v8');
21+
const util = require('node:util');
22+
const timers = require('node:timers');
23+
24+
const sleep = util.promisify(timers.setTimeout);
25+
26+
const run = func;
27+
28+
const MB = (2 ** 10) ** 2;
29+
30+
async function main() {
31+
const startingMemoryUsed = process.memoryUsage().heapUsed / MB;
32+
process.send({ startingMemoryUsed });
33+
34+
for (let iteration = 0; iteration < iterations; iteration++) {
35+
await run({ MongoClient, uri, iteration });
36+
global.gc();
37+
}
38+
39+
global.gc();
40+
// Sleep b/c maybe gc will run
41+
await sleep(100);
42+
global.gc();
43+
44+
const endingMemoryUsed = process.memoryUsage().heapUsed / MB;
45+
process.send({ endingMemoryUsed });
46+
v8.writeHeapSnapshot(`${name}.heapsnapshot.json`);
47+
}
48+
49+
main()
50+
.then(() => {
51+
process.exit(0);
52+
})
53+
.catch(() => {
54+
process.exit(1);
55+
});

test/integration/node-specific/client_close.test.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { expect } from 'chai';
12
import { TestConfiguration } from '../../tools/runner/config';
23
import { runScriptAndReturnResourceInfo } from './resource_tracking_script_builder';
34

4-
describe.only('client.close() Integration', () => {
5+
describe.skip('client.close() Integration', () => {
56
let config: TestConfiguration;
67
beforeEach(function () {
78
config = this.configuration;
@@ -21,44 +22,41 @@ describe.only('client.close() Integration', () => {
2122
});
2223

2324
describe('MongoClientAuthProviders', () => {
24-
describe('when MongoClientAuthProviders is instantiated', () => {
25-
it('the token cache is cleaned up by client.close', () => {
25+
describe('when MongoClientAuthProviders is instantiated and token file read hangs', () => {
26+
it('the file read is interrupted by client.close', () => {
2627
});
2728
});
2829
});
2930

3031
describe('Topology', () => {
31-
describe('after a Topology is explicitly created', () => {
32-
it('timers are cleaned up by client.close()', () => {
33-
34-
});
35-
});
3632
describe('after a Topology is created through client.connect()', () => {
37-
it('timers are cleaned up by client.close()', () => {
38-
33+
it('server selection timers are cleaned up by client.close()', async () => {
34+
await runScriptAndReturnResourceInfo(
35+
'topology-clean-up',
36+
config,
37+
async function run({ MongoClient, uri }) {
38+
const client = new MongoClient(uri);
39+
await client.connect();
40+
await client.close();
41+
}
42+
);
3943
});
4044
});
4145
});
4246

4347
describe('SRVPoller', () => {
44-
describe('after SRVPoller is explicitly created', () => {
45-
it('timers are cleaned up by client.close()', () => {
46-
47-
});
48-
});
49-
5048
// SRVPoller is implicitly created after an SRV string's topology transitions to sharded
51-
describe('after SRVPoller is implicitly created', () => {
49+
describe('after SRVPoller is created', () => {
5250
it('timers are cleaned up by client.close()', () => {
5351

5452
});
5553
});
5654
});
5755

5856
describe('ClientSession', () => {
59-
describe('after a clientSession is created', () => {
57+
describe('after a clientSession is created and used', () => {
6058
it('the server-side ServerSession and transaction are cleaned up by client.close()', () => {
61-
59+
// must send a command to the server
6260
});
6361
});
6462
});
@@ -67,9 +65,6 @@ describe.only('client.close() Integration', () => {
6765
describe('when FLE is enabled and the client has made a KMS request', () => {
6866
it('no sockets remain after client.close', () => {
6967

70-
});
71-
it('no server-side connection threads remain after client.close', () => {
72-
7368
});
7469
describe('when the TLS file read hangs', () => {
7570
it('the file read is interrupted by client.close', () => {
@@ -79,6 +74,10 @@ describe.only('client.close() Integration', () => {
7974
});
8075
});
8176

77+
describe('Server', () => {
78+
79+
});
80+
8281
describe('ConnectionPool', () => {
8382
describe('after new connection pool is created', () => {
8483
it('minPoolSize timer is cleaned up by client.close()', () => {
@@ -95,22 +94,23 @@ describe.only('client.close() Integration', () => {
9594
});
9695

9796
describe('after a heartbeat fails', () => {
98-
it('monitor interval timer is cleaned up by client.close()', () => {
97+
it('the new monitor interval timer is cleaned up by client.close()', () => {
9998

10099
});
101100
});
102101
});
103102

104103
describe('RTTPinger', () => {
105-
describe('after helloReply has a topologyVersion defined fails', () => {
106-
it('rtt pinger timer is cleaned up by client.close()', () => {
107-
104+
describe('after entering monitor streaming mode ', () => {
105+
it('the rtt pinger timer is cleaned up by client.close()', () => {
106+
// helloReply has a topologyVersion defined
108107
});
109108
});
110109
});
111110

112111
describe('Connection', () => {
113112
describe('when connection monitoring is turned on', () => {
113+
// connection monitoring is by default turned on - with the exception of load-balanced mode
114114
it('no sockets remain after client.close', () => {
115115

116116
});

test/integration/node-specific/resource_tracking_script_builder.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ export async function runScriptAndReturnResourceInfo(
117117
func: ResourceTestFunction
118118
) {
119119

120-
const scriptName = `scripts/${name}.cjs`;
120+
const scriptName = `${name}.cjs`;
121121
const scriptContent = await testScriptFactory(name, config.url(), REPORT_RESOURCE_SCRIPT_PATH, func);
122122
await writeFile(scriptName, scriptContent, { encoding: 'utf8' });
123123

124124
const processDiedController = new AbortController();
125-
const script = fork(name);
125+
const script = fork(scriptName);
126126

127127
// Interrupt our awaiting of messages if the process crashed
128128
script.once('close', exitCode => {
@@ -133,11 +133,19 @@ export async function runScriptAndReturnResourceInfo(
133133

134134
const willClose = once(script, 'close');
135135

136+
const messages = on(script, 'message', { signal: processDiedController.signal });
137+
const report = await messages.next();
138+
let { finalReport, originalReport } = report.value[0];
139+
140+
// const beforeExit = await messages.next();
141+
136142
// make sure the process ended
137143
const [exitCode] = await willClose;
144+
145+
// assertions about exit status
138146
expect(exitCode, 'process should have exited with zero').to.equal(0);
139147

140-
const messages = on(script, 'message', { signal: processDiedController.signal });
141-
const report = await messages.next();
142-
return report;
148+
// assertions about clean-up
149+
expect(originalReport.length).to.equal(finalReport.length);
150+
// expect(beforeExitEventHappened).to.be.true;
143151
}

test/tools/fixtures/close_resource_script.in.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ const driverPath = DRIVER_SOURCE_PATH;
66
const func = FUNCTION_STRING;
77
const name = NAME_STRING;
88
const uri = URI_STRING;
9-
const iterations = ITERATIONS_STRING;
109

1110
const { MongoClient } = require(driverPath);
1211
const process = require('node:process');
@@ -18,11 +17,12 @@ const run = func;
1817

1918
async function main() {
2019
process.on('beforeExit', (code) => {
21-
process.send({beforeExit: true});
20+
console.log('Process beforeExit event with code: ', code);
2221
});
23-
await run({ MongoClient, uri, iteration });
24-
const report = process.report.getReport();
25-
process.send({ report });
22+
const originalReport = process.report.getReport().libuv;
23+
await run({ MongoClient, uri });
24+
const finalReport = process.report.getReport().libuv;
25+
process.send({originalReport, finalReport});
2626
}
2727

2828
main()

topology-clean-up.cjs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
/* eslint-disable no-undef */
4+
5+
const driverPath = "/Users/aditi.khare/Desktop/node-mongodb-native/lib";
6+
const func = (async function run({ MongoClient, uri }) {
7+
const client = new MongoClient(uri);
8+
await client.connect();
9+
await client.close();
10+
});
11+
const name = "topology-clean-up";
12+
const uri = "mongodb://bob:pwd123@localhost:31000/integration_tests?replicaSet=rs&authSource=admin";
13+
14+
const { MongoClient } = require(driverPath);
15+
const process = require('node:process');
16+
const v8 = require('node:v8');
17+
const util = require('node:util');
18+
const timers = require('node:timers');
19+
20+
const run = func;
21+
22+
async function main() {
23+
process.on('beforeExit', (code) => {
24+
console.log('Process beforeExit event with code: ', code);
25+
});
26+
const originalReport = process.report.getReport().libuv;
27+
await run({ MongoClient, uri });
28+
const finalReport = process.report.getReport().libuv;
29+
process.send({originalReport, finalReport});
30+
}
31+
32+
main()
33+
.then(() => {
34+
process.exit(0);
35+
})
36+
.catch(() => {
37+
process.exit(1);
38+
});

topology.cjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
3+
/* eslint-disable no-undef */
4+
5+
const driverPath = "/Users/aditi.khare/Desktop/node-mongodb-native/lib";
6+
const func = (async function run({ MongoClient, uri }) {
7+
const mongoClient = new MongoClient(uri);
8+
await mongoClient.connect();
9+
});
10+
const name = "topology";
11+
const uri = "mongodb://bob:pwd123@localhost:31000/integration_tests?replicaSet=rs&authSource=admin";
12+
const iterations = ITERATIONS_STRING;
13+
14+
const { MongoClient } = require(driverPath);
15+
const process = require('node:process');
16+
const v8 = require('node:v8');
17+
const util = require('node:util');
18+
const timers = require('node:timers');
19+
20+
const run = func;
21+
22+
async function main() {
23+
process.on('beforeExit', (code) => {
24+
process.send({beforeExit: true});
25+
});
26+
await run({ MongoClient, uri, iteration });
27+
const report = process.report.getReport();
28+
process.send({ report });
29+
}
30+
31+
main()
32+
.then(() => {
33+
process.exit(0);
34+
})
35+
.catch(() => {
36+
process.exit(1);
37+
});

0 commit comments

Comments
 (0)