-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
11 changed files
with
845 additions
and
45 deletions.
There are no files selected for viewing
93 changes: 93 additions & 0 deletions
93
...egration/connection-monitoring-and-pooling/connection_monitoring_and_pooling.spec.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import { HostAddress, MongoClient } from '../../../src'; | ||
import { shuffle } from '../../../src/utils'; | ||
import { loadSpecTests } from '../../spec'; | ||
import { CmapTest, runCmapTest, ThreadContext } from '../../tools/cmap_spec_runner'; | ||
import { isAnyRequirementSatisfied } from '../../tools/unified-spec-runner/unified-utils'; | ||
|
||
// These tests rely on a simple "pool.clear()" command, which is not sufficient | ||
// to properly clear the pool in LB mode, since it requires a serviceId to be passed in | ||
const LB_SKIP_TESTS = [ | ||
'must destroy checked in connection if it is stale', | ||
'must destroy and must not check out a stale connection if found while iterating available connections' | ||
]; | ||
|
||
describe('Connection Monitoring and Pooling Spec Tests (Integration)', function () { | ||
const suites: CmapTest[] = loadSpecTests('connection-monitoring-and-pooling'); | ||
|
||
for (const test of suites.filter(test => { | ||
// TODO(NODE-2993): unskip integration tests for maxConnecting | ||
return test.style === 'unit'; | ||
})) { | ||
describe(test.description, function () { | ||
let hostAddress: HostAddress, threadContext: ThreadContext, client: MongoClient; | ||
|
||
beforeEach(async function () { | ||
let utilClient: MongoClient; | ||
if (this.configuration.isLoadBalanced) { | ||
if (LB_SKIP_TESTS.some(testDescription => testDescription === test.description)) { | ||
this.currentTest.skipReason = 'cannot run against a load balanced environment'; | ||
this.skip(); | ||
} | ||
// The util client can always point at the single mongos LB frontend. | ||
utilClient = this.configuration.newClient(this.configuration.singleMongosLoadBalancerUri); | ||
} else { | ||
utilClient = this.configuration.newClient(); | ||
} | ||
|
||
await utilClient.connect(); | ||
|
||
const allRequirements = test.runOn || []; | ||
|
||
const someRequirementMet = | ||
!allRequirements.length || | ||
(await isAnyRequirementSatisfied(this.currentTest.ctx, allRequirements, utilClient)); | ||
|
||
if (!someRequirementMet) { | ||
await utilClient.close(); | ||
this.skip(); | ||
// NOTE: the rest of the code below won't execute after the skip is invoked | ||
} | ||
|
||
try { | ||
const serverMap = utilClient.topology.s.description.servers; | ||
const hosts = shuffle(serverMap.keys()); | ||
const selectedHostUri = hosts[0]; | ||
hostAddress = serverMap.get(selectedHostUri).hostAddress; | ||
threadContext = new ThreadContext( | ||
hostAddress, | ||
this.configuration.isLoadBalanced ? { loadBalanced: true } : {} | ||
); | ||
|
||
if (test.failPoint) { | ||
client = this.configuration.newClient( | ||
`mongodb://${hostAddress}/${ | ||
this.configuration.isLoadBalanced ? '?loadBalanced=true' : '?directConnection=true' | ||
}` | ||
); | ||
await client.connect(); | ||
await client.db('admin').command(test.failPoint); | ||
} | ||
} finally { | ||
await utilClient.close(); | ||
} | ||
}); | ||
|
||
afterEach(async function () { | ||
await threadContext?.tearDown(); | ||
if (!client) { | ||
return; | ||
} | ||
if (test.failPoint) { | ||
await client | ||
.db('admin') | ||
.command({ configureFailPoint: test.failPoint.configureFailPoint, mode: 'off' }); | ||
} | ||
await client.close(); | ||
}); | ||
|
||
it('should pass', async function () { | ||
await runCmapTest(test, threadContext); | ||
}); | ||
}); | ||
} | ||
}); |
104 changes: 104 additions & 0 deletions
104
test/spec/connection-monitoring-and-pooling/pool-checkout-maxConnecting-is-enforced.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
{ | ||
"version": 1, | ||
"style": "integration", | ||
"description": "maxConnecting is enforced", | ||
"runOn": [ | ||
{ | ||
"minServerVersion": "4.4.0" | ||
} | ||
], | ||
"failPoint": { | ||
"configureFailPoint": "failCommand", | ||
"mode": { | ||
"times": 50 | ||
}, | ||
"data": { | ||
"failCommands": [ | ||
"isMaster", | ||
"hello" | ||
], | ||
"closeConnection": false, | ||
"blockConnection": true, | ||
"blockTimeMS": 750 | ||
} | ||
}, | ||
"poolOptions": { | ||
"maxPoolSize": 10, | ||
"waitQueueTimeoutMS": 5000 | ||
}, | ||
"operations": [ | ||
{ | ||
"name": "start", | ||
"target": "thread1" | ||
}, | ||
{ | ||
"name": "start", | ||
"target": "thread2" | ||
}, | ||
{ | ||
"name": "start", | ||
"target": "thread3" | ||
}, | ||
{ | ||
"name": "checkOut", | ||
"thread": "thread1" | ||
}, | ||
{ | ||
"name": "waitForEvent", | ||
"event": "ConnectionCreated", | ||
"count": 1 | ||
}, | ||
{ | ||
"name": "wait", | ||
"ms": 100 | ||
}, | ||
{ | ||
"name": "checkOut", | ||
"thread": "thread2" | ||
}, | ||
{ | ||
"name": "checkOut", | ||
"thread": "thread3" | ||
}, | ||
{ | ||
"name": "waitForEvent", | ||
"event": "ConnectionReady", | ||
"count": 3 | ||
} | ||
], | ||
"events": [ | ||
{ | ||
"type": "ConnectionCreated", | ||
"address": 42, | ||
"connectionId": 1 | ||
}, | ||
{ | ||
"type": "ConnectionCreated", | ||
"address": 42 | ||
}, | ||
{ | ||
"type": "ConnectionReady", | ||
"address": 42, | ||
"connectionId": 1 | ||
}, | ||
{ | ||
"type": "ConnectionCreated", | ||
"address": 42 | ||
}, | ||
{ | ||
"type": "ConnectionReady", | ||
"address": 42 | ||
}, | ||
{ | ||
"type": "ConnectionReady", | ||
"address": 42 | ||
} | ||
], | ||
"ignore": [ | ||
"ConnectionCheckOutStarted", | ||
"ConnectionCheckedIn", | ||
"ConnectionCheckedOut", | ||
"ConnectionClosed", | ||
"ConnectionPoolCreated" | ||
] | ||
} |
77 changes: 77 additions & 0 deletions
77
test/spec/connection-monitoring-and-pooling/pool-checkout-maxConnecting-is-enforced.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
version: 1 | ||
style: integration | ||
description: maxConnecting is enforced | ||
runOn: | ||
- | ||
# required for blockConnection in fail point | ||
minServerVersion: "4.4.0" | ||
failPoint: | ||
configureFailPoint: failCommand | ||
# high amount to ensure not interfered with by monitor checks. | ||
mode: { times: 50 } | ||
data: | ||
failCommands: ["isMaster","hello"] | ||
closeConnection: false | ||
blockConnection: true | ||
blockTimeMS: 750 | ||
poolOptions: | ||
maxPoolSize: 10 | ||
waitQueueTimeoutMS: 5000 | ||
operations: | ||
# start 3 threads | ||
- name: start | ||
target: thread1 | ||
- name: start | ||
target: thread2 | ||
- name: start | ||
target: thread3 | ||
# start creating a Connection. This will take a while | ||
# due to the fail point. | ||
- name: checkOut | ||
thread: thread1 | ||
# wait for thread1 to actually start creating a Connection | ||
- name: waitForEvent | ||
event: ConnectionCreated | ||
count: 1 | ||
# wait some more time to ensure thread1 has begun establishing a Connection | ||
- name: wait | ||
ms: 100 | ||
# start 2 check out requests. Only one thread should | ||
# start creating a Connection and the other one should be | ||
# waiting for pendingConnectionCount to be less than maxConnecting, | ||
# only starting once thread1 finishes creating its Connection. | ||
- name: checkOut | ||
thread: thread2 | ||
- name: checkOut | ||
thread: thread3 | ||
# wait until all Connections have been created. | ||
- name: waitForEvent | ||
event: ConnectionReady | ||
count: 3 | ||
events: | ||
# thread1 creates its connection | ||
- type: ConnectionCreated | ||
address: 42 | ||
connectionId: 1 | ||
# either thread2 or thread3 creates its connection | ||
# the other thread is stuck waiting for maxConnecting to come down | ||
- type: ConnectionCreated | ||
address: 42 | ||
# thread1 finishes establishing its connection, freeing | ||
# up the blocked thread to start establishing | ||
- type: ConnectionReady | ||
address: 42 | ||
connectionId: 1 | ||
- type: ConnectionCreated | ||
address: 42 | ||
# the remaining two Connections finish establishing | ||
- type: ConnectionReady | ||
address: 42 | ||
- type: ConnectionReady | ||
address: 42 | ||
ignore: | ||
- ConnectionCheckOutStarted | ||
- ConnectionCheckedIn | ||
- ConnectionCheckedOut | ||
- ConnectionClosed | ||
- ConnectionPoolCreated |
99 changes: 99 additions & 0 deletions
99
test/spec/connection-monitoring-and-pooling/pool-checkout-maxConnecting-timeout.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
{ | ||
"version": 1, | ||
"style": "integration", | ||
"description": "waiting on maxConnecting is limited by WaitQueueTimeoutMS", | ||
"runOn": [ | ||
{ | ||
"minServerVersion": "4.4.0" | ||
} | ||
], | ||
"failPoint": { | ||
"configureFailPoint": "failCommand", | ||
"mode": { | ||
"times": 50 | ||
}, | ||
"data": { | ||
"failCommands": [ | ||
"isMaster", | ||
"hello" | ||
], | ||
"closeConnection": false, | ||
"blockConnection": true, | ||
"blockTimeMS": 750 | ||
} | ||
}, | ||
"poolOptions": { | ||
"maxPoolSize": 10, | ||
"waitQueueTimeoutMS": 50 | ||
}, | ||
"operations": [ | ||
{ | ||
"name": "start", | ||
"target": "thread1" | ||
}, | ||
{ | ||
"name": "checkOut", | ||
"thread": "thread1" | ||
}, | ||
{ | ||
"name": "start", | ||
"target": "thread2" | ||
}, | ||
{ | ||
"name": "checkOut", | ||
"thread": "thread2" | ||
}, | ||
{ | ||
"name": "waitForEvent", | ||
"event": "ConnectionCreated", | ||
"count": 2 | ||
}, | ||
{ | ||
"name": "start", | ||
"target": "thread3" | ||
}, | ||
{ | ||
"name": "checkOut", | ||
"thread": "thread3" | ||
}, | ||
{ | ||
"name": "waitForEvent", | ||
"event": "ConnectionCheckOutFailed", | ||
"count": 1 | ||
}, | ||
{ | ||
"name": "waitForThread", | ||
"target": "thread3" | ||
} | ||
], | ||
"error": { | ||
"type": "WaitQueueTimeoutError", | ||
"message": "Timed out while checking out a connection from connection pool" | ||
}, | ||
"events": [ | ||
{ | ||
"type": "ConnectionCheckOutStarted", | ||
"address": 42 | ||
}, | ||
{ | ||
"type": "ConnectionCheckOutStarted", | ||
"address": 42 | ||
}, | ||
{ | ||
"type": "ConnectionCheckOutStarted", | ||
"address": 42 | ||
}, | ||
{ | ||
"type": "ConnectionCheckOutFailed", | ||
"reason": "timeout", | ||
"address": 42 | ||
} | ||
], | ||
"ignore": [ | ||
"ConnectionCreated", | ||
"ConnectionCheckedIn", | ||
"ConnectionCheckedOut", | ||
"ConnectionClosed", | ||
"ConnectionPoolCreated" | ||
] | ||
} |
Oops, something went wrong.