Skip to content

Commit

Permalink
test(NODE-4165): sync maxConnecting spec tests and update runner (#3239)
Browse files Browse the repository at this point in the history
  • Loading branch information
dariakp committed May 10, 2022
1 parent c6a2ddd commit 15f8870
Show file tree
Hide file tree
Showing 11 changed files with 845 additions and 45 deletions.
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);
});
});
}
});
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"
]
}
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
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"
]
}

0 comments on commit 15f8870

Please sign in to comment.