-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
test(NODE-6631): Implement integration tests for improved client.close() - sockets + timers #4361
base: main
Are you sure you want to change the base?
Conversation
…cript vars/functions
There is an existing patch(es) for this commit SHA: Please note that the status that is posted is not in the context of this PR but rather the (latest) existing patch and that may affect some tests that may depend on the particular PR. If your tests do not rely on any PR-specific values (like base or head branch name) then your tests will report the same status. If you would like a patch to run in the context of this PR and abort the other(s), comment 'evergreen retry'. |
617e9af
to
13a7f27
Compare
54579bd
to
78f787f
Compare
028bf63
to
2a43e4d
Compare
!originalReportAddresses.includes(resource.address) && | ||
resource.is_referenced && // if a resource is unreferenced, it's not keeping the event loop open | ||
(!serverType.includes(resource.type) || resource.is_active) | ||
!originalReportAddresses.includes(resource.address) && resource.is_referenced // if a resource is unreferenced, it's not keeping the event loop open |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow-up from NODE-6620: We do want to clean up inactive sockets per Slack discussion
|
||
const servers = client.topology?.s.servers; | ||
|
||
// note: minPoolSizeCheckFrequencyMS = 100 ms by client, so this test has a chance of being flaky |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See the note on the comment. This test has a higher chance of being flaky since the client can't set minPoolSizeCheckFrequencyMS
. I can this to set the variable to a higher value using sinon if preferred by reviewers.
9793c44
to
f003454
Compare
e97cc3c
to
4865259
Compare
updated tests delete extraneous files srv test lint
4865259
to
59fda80
Compare
let serverSelectionTimeoutStarted = false; | ||
|
||
// make server selection hang so check out timer isn't cleared and check that the timeout has started | ||
sinon.stub(Promise, 'race').callsFake(async ([_serverPromise, timeout]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we test against a replicaset and use a ReadPreference that doesn't match any servers then we can be sure we're stuck in server selection until the timer fires. Then we won't need to sinon spy or stub here.
This is how I'm testing server selection interruption for signal support:
https://github.com/mongodb/node-mongodb-native/blob/NODE-6258-abortsignal/test/integration/node-specific/abort_signal.test.ts#L201-L244
I'm also seeing an error when I skip over the resource assertions:
TypeError: Cannot read properties of undefined (reading 'setTimeout')
client.on('serverHeartbeatSucceeded', () => (heartbeatHappened = true)); | ||
await client.connect(); | ||
await sleep(heartbeatFrequencyMS * 2.5); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if we awaited the 'serverHeartbeatSucceeded' event directly instead of sleeping for some amount of time?
function getMonitorTimer(servers) { | ||
for (const server of servers) { | ||
return server[1]?.monitor.monitorId.timerId; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about topologies other than standalone should we be returning more than the first timer?
const servers = client.topology.s.servers; | ||
expect(getMonitorTimer(servers)).to.exist; | ||
await client.close(); | ||
expect(getMonitorTimer(servers)).to.not.exist; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly but I don't think we need to check that it has been set to null/undefined because if it was left on there it wouldn't be wrong as long as it is still cleared in the "resource" sense.
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ | ||
const run = async function ({ MongoClient, uri, expect, sleep, getTimerCount }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The nice part about giving all the inputs as an object that we can pick and chose the inputs by simply omitting the dependencies we aren't using. So if you remove uri then you can remove the lint exemption
}; | ||
await utilClient.db('admin').command(failPoint); | ||
|
||
const timeoutStartedSpy = sinon.spy(timers, 'setTimeout'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm seeing an error thrown for this the same way it was for the server selection test. I don't think we need the spy if we know we have a commandStarted on a client with maxPoolSize: 1
const timeoutStartedSpy = sinon.spy(timers, 'setTimeout'); | ||
|
||
const client = new MongoClient(uri, { | ||
minPoolSize: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would only set the max so that we don't create the timer for satisfying minPoolSize, not necessarily a problem but more resources that we need to make for this test.
|
||
await utilClient.close(); | ||
|
||
const err = await insertPromise; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the first insertPromise succeed (just after a long time), its the second one that won't be able to complete connection checkout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was confused / surprised about this as well. If we await both of them, the first one fails and the second one succeeds.
process.report.getReport().libuv.filter(r => r.type === 'tcp'); | ||
|
||
// assert no sockets to start with | ||
expect(connectionMonitoringReport()).to.have.length(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expect(connectionMonitoringReport()).to.have.length(0); | |
expect(connectionMonitoringReport()).to.have.lengthOf(0); |
I could be wrong but I think you have to use lengthOf
const infiniteFile = '/dev/zero'; | ||
|
||
const kmsProviders = BSON.EJSON.parse(process.env.CSFLE_KMS_PROVIDERS); | ||
const kmsProviders = mongodb.BSON.EJSON.parse(process.env.CSFLE_KMS_PROVIDERS); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test fails locally when CSFLE_KMS_PROVIDERS isn't defined, which is the default, can you put the metadata on this test to have it skip unless encryption is enabled?
Description
Add socket integration tests for client.close().
What is changing?
libuv
tracking for each relevant driver instance of socket creation.process.getActiveResourceInfo()
MonitorInterval
's timer exitsTo see more information regarding testing plan outline see the design document, specifically the dropdowns under Sockets and Timers sections, respectively.
Is there new documentation needed for these changes?
No
What is the motivation for this change?
Improved client.close()
Release Highlight
Double check the following
npm run check:lint
scripttype(NODE-xxxx)[!]: description
feat(NODE-1234)!: rewriting everything in coffeescript