Skip to content

Commit 4798bc2

Browse files
skeleton updates
1 parent 0af55e9 commit 4798bc2

File tree

2 files changed

+170
-67
lines changed

2 files changed

+170
-67
lines changed

test/integration/client-close/client_close.test.ts

Lines changed: 127 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,136 +1,196 @@
1+
import { fork } from 'child_process';
12
import {
23
MongoClient,
34
} from '../../mongodb';
5+
import { on, once } from 'node:events';
6+
import { readFile, unlink, writeFile } from 'node:fs/promises';
7+
import { TestConfiguration } from '../../tools/runner/config';
8+
import { expect } from 'chai';
9+
import { StringOrPlaceholder } from '../../tools/unified-spec-runner/schema';
410

511
/*
6-
async function runWithProcessAndCheck(_fn) {
7-
start process
8-
Run fn in process
9-
Assert no resources
10-
Close process
11-
}
12+
export async function testScriptFactory(
13+
name: string,
14+
uri: string,
15+
iterations: number,
16+
func: Function
17+
) {
18+
let resourceScript = await readFile(RESOURCE_SCRIPT_PATH, { encoding: 'utf8' });
19+
20+
resourceScript = resourceScript.replace('DRIVER_SOURCE_PATH', DRIVER_SRC_PATH);
21+
resourceScript = resourceScript.replace('FUNCTION_STRING', `(${func.toString()})`);
22+
resourceScript = resourceScript.replace('NAME_STRING', JSON.stringify(name));
23+
resourceScript = resourceScript.replace('URI_STRING', JSON.stringify(uri));
24+
resourceScript = resourceScript.replace('ITERATIONS_STRING', `${iterations}`);
25+
26+
return resourceScript;
27+
}
28+
29+
export async function runScriptAndReturnResourceInfo(
30+
name: string,
31+
config: TestConfiguration,
32+
func: Function
33+
) {
34+
35+
const pathName = `scripts/${name}.cjs`;
36+
const scriptContent = await testScriptFactory(name, config.url(), func);
37+
await writeFile(name, func.toString(), { encoding: 'utf8' });
38+
39+
const processDiedController = new AbortController();
40+
const script = fork(name, { execArgv: ['--expose-gc'] });
41+
42+
// Interrupt our awaiting of messages if the process crashed
43+
script.once('close', exitCode => {
44+
if (exitCode !== 0) {
45+
processDiedController.abort(new Error(`process exited with: ${exitCode}`));
46+
}
47+
});
48+
49+
const willClose = once(script, 'close');
50+
51+
// make sure the process ended
52+
const [exitCode] = await willClose;
53+
expect(exitCode, 'process should have exited with zero').to.equal(0);
54+
55+
return process.report.getReport().libuv;
56+
}
1257
*/
1358

14-
describe.only('client.close() Resource Management Integration tests', () => {
59+
describe.only('client.close() Integration', () => {
1560
let client: MongoClient;
61+
let config: TestConfiguration;
1662
beforeEach(function () {
63+
config = this.configuration;
1764
client = this.configuration.newClient();
1865
});
1966

2067
describe('File System', () => {
21-
context('when client is closed', () => {
22-
context('after client is connected', () => {
23-
it('the TLS file access is cleaned up', () => {
68+
describe('when client is connected and reading a TLS long file', () => {
69+
it('the file read is interrupted by client.close', () => {
2470

25-
});
2671
});
27-
context('after client is created ', () => {
28-
// our docker env detection uses fs.access which will not be aborted until after it runs
29-
// fs.access does not support abort signals
30-
it('the .docker file access is cleaned up', () => {
31-
32-
});
72+
});
73+
describe('when client is created and reading a long docker file', () => {
74+
// our docker env detection uses fs.access which will not be aborted until after it runs
75+
// fs.access does not support abort signals
76+
it('the file read is not interrupted by client.close', () => {
3377
});
78+
});
3479

35-
context('when FLE is enabled', () => {
36-
context('after client has made a KMS request', () => {
37-
it('the TLS file access is cleaned up', () => {
80+
describe('when FLE is enabled and the client has made a KMS request that is reading a long TLS file', () => {
81+
it('the file read is interrupted by client.close', () => {
3882

39-
});
40-
});
4183
});
4284
});
4385
});
4486

4587
describe('Connection Creation and Socket Lifetime', () => {
46-
context('when client is closed', () => {
47-
context('after client is connected', () => {
48-
it('the socket is cleaned up', () => {
88+
describe('after client is connected', () => {
89+
it('no sockets remain after client.close', () => {
4990

50-
});
5191
});
92+
it('no server-side connection threads remain after client.close', () => {
5293

53-
context('after a connection is checked out', () => {
54-
it('the socket is cleaned up', () => {
94+
});
95+
});
96+
97+
describe('after a connection is checked out', () => {
98+
it('no sockets remain after client.close', () => {
99+
100+
});
101+
it('no server-side connection threads remain after client.close', () => {
55102

56-
});
57103
});
104+
});
58105

59-
context('after a minPoolSize has been set on the ConnectionPool', () => {
60-
it('the socket is cleaned up', () => {
106+
describe('after a minPoolSize has been set on the ConnectionPool', () => {
107+
it('no sockets remain after client.close', () => {
61108

62-
});
63109
});
110+
it('no server-side connection threads remain after client.close', () => {
111+
112+
});
113+
});
114+
115+
describe('when connection monitoring is turned on', () => {
116+
it('no sockets remain after client.close', () => {
64117

65-
context('when connection monitoring is turned on', () => {
66-
it('the socket is cleaned up', () => {
118+
});
119+
it('no server-side connection threads remain after client.close', () => {
67120

68-
});
69121
});
122+
});
70123

71-
context('when rtt monitoring is turned on', () => {
72-
it('the socket is cleaned up', () => {
124+
describe('when rtt monitoring is turned on', () => {
125+
it('no sockets remain after client.close', () => {
73126

74-
});
75127
});
128+
it('no server-side connection threads remain after client.close', () => {
129+
130+
});
131+
});
76132

77-
context('when FLE is enabled', () => {
78-
context('after client has made a KMS request', () => {
79-
it('the socket is cleaned up', () => {
133+
describe('when FLE is enabled and the client has made a KMS request', () => {
134+
it('no sockets remain after client.close', () => {
135+
136+
});
137+
it('no server-side connection threads remain after client.close', () => {
80138

81-
});
82-
});
83139
});
84140
});
85141
});
86142

87143
describe('Timers', () => {
88-
context('when client is closed', () => {
89-
context('after SRVPoller is explicitly created', () => {
90-
it('timers are cleaned up', () => {
144+
describe('after SRVPoller is explicitly created', () => {
145+
it('timers are cleaned up by client.close()', () => {
91146

92-
});
93147
});
148+
});
94149

95-
// SRVPoller is implicitly created after an SRV string's topology transitions to sharded
96-
context('after SRVPoller is implicitly created', () => {
97-
it('timers are cleaned up', () => {
150+
// SRVPoller is implicitly created after an SRV string's topology transitions to sharded
151+
describe('after SRVPoller is implicitly created', () => {
152+
it('timers are cleaned up by client.close()', () => {
98153

99-
});
100154
});
155+
});
101156

102-
context('after new connection pool is created', () => {
103-
it('minPoolSize timer is cleaned up', () => {
157+
describe('after new connection pool is created', () => {
158+
it('minPoolSize timer is cleaned up by client.close()', () => {
104159

105-
});
106160
});
161+
});
107162

108-
context('after a new monitor is made', () => {
109-
it('monitor interval timer is cleaned up', () => {
163+
describe('after a new monitor is made', () => {
164+
it('monitor interval timer is cleaned up by client.close()', () => {
110165

111-
});
112166
});
167+
});
113168

114-
context('after a heartbeat fails', () => {
115-
it('monitor interval timer is cleaned up', () => {
169+
describe('after a heartbeat fails', () => {
170+
it('monitor interval timer is cleaned up by client.close()', () => {
116171

117-
});
118172
});
173+
});
119174

120-
context('after helloReply has a topologyVersion defined fails', () => {
121-
it('rtt pinger timer is cleaned up', () => {
175+
describe('after helloReply has a topologyVersion defined fails', () => {
176+
it('rtt pinger timer is cleaned up by client.close()', () => {
122177

123-
});
124178
});
125179
});
126180
});
127181

128182
describe('Cursor Clean-up', () => {
129-
context('when client is closed', () => {
130-
context('after cursors are created', () => {
131-
it('closes all active cursors', () => {
183+
describe('after cursors are created', () => {
184+
it('all active server-side cursors are closed by client.close()', () => {
185+
186+
});
187+
});
188+
});
189+
190+
describe('Sessions', () => {
191+
describe('after a clientSession is created', () => {
192+
it('the server-side ServerSession is cleaned up by client.close()', () => {
132193

133-
});
134194
});
135195
});
136196
});
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict';
2+
3+
/* eslint-disable no-undef */
4+
5+
const driverPath = DRIVER_SOURCE_PATH;
6+
const func = FUNCTION_STRING;
7+
const name = NAME_STRING;
8+
const uri = URI_STRING;
9+
const iterations = ITERATIONS_STRING;
10+
11+
const { MongoClient } = require(driverPath);
12+
const process = require('node:process');
13+
const v8 = require('node:v8');
14+
const util = require('node:util');
15+
const timers = require('node:timers');
16+
17+
const sleep = util.promisify(timers.setTimeout);
18+
19+
const run = func;
20+
21+
const MB = (2 ** 10) ** 2;
22+
23+
async function main() {
24+
for (let iteration = 0; iteration < iterations; iteration++) {
25+
await run({ MongoClient, uri, iteration });
26+
global.gc();
27+
}
28+
29+
global.gc();
30+
// Sleep b/c maybe gc will run
31+
await sleep(100);
32+
global.gc();
33+
34+
process.send({ process.report.getReport()});
35+
}
36+
37+
main()
38+
.then(() => {
39+
process.exit(0);
40+
})
41+
.catch(() => {
42+
process.exit(1);
43+
});

0 commit comments

Comments
 (0)