Skip to content

Commit 3886127

Browse files
daprahamianmbroadst
authored andcommitted
feat(transactions): support pinning mongos for sharded txns
* test: enable starting mongos with test commands * add proxy metadata to mongos environment * test: let transaction tests run against mongos * test: run outcome validation after turning endpoints off * test: up min pool size to get around pool bug * test: enable mongos pinning tests * test: make mongos test only run against a single mongos * updating to run properly * remove minSize, as it is not necessary NODE-1743
1 parent f08603f commit 3886127

File tree

2 files changed

+97
-43
lines changed

2 files changed

+97
-43
lines changed

test/environments.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,14 @@ class ShardedEnvironment extends EnvironmentBase {
174174
{
175175
bind_ip: 'localhost',
176176
port: 51000,
177-
configdb: 'localhost:35000,localhost:35001,localhost:35002'
177+
configdb: 'localhost:35000,localhost:35001,localhost:35002',
178+
setParameter: ['enableTestCommands=1']
178179
},
179180
{
180181
bind_ip: 'localhost',
181182
port: 51001,
182-
configdb: 'localhost:35000,localhost:35001,localhost:35002'
183+
configdb: 'localhost:35000,localhost:35001,localhost:35002',
184+
setParameter: ['enableTestCommands=1']
183185
}
184186
];
185187

@@ -195,6 +197,10 @@ class ShardedEnvironment extends EnvironmentBase {
195197
return x;
196198
});
197199

200+
this.proxies = proxyNodes.map(proxy => {
201+
return { host: proxy.bind_ip, port: proxy.port };
202+
});
203+
198204
Promise.all([
199205
this.manager.addShard(nodes1, { replSet: 'rs1' }),
200206
this.manager.addShard(nodes2, { replSet: 'rs2' })

test/functional/transactions_tests.js

+89-41
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,57 @@ class TransactionsTestContext {
9191
constructor() {
9292
this.url = null;
9393
this.sharedClient = null;
94+
this.failPointClients = [];
95+
}
96+
97+
runForAllClients(fn) {
98+
const allClients = [this.sharedClient].concat(this.failPointClients);
99+
return Promise.all(allClients.map(fn));
100+
}
101+
102+
runFailPointCmd(fn) {
103+
return this.failPointClients.length
104+
? Promise.all(this.failPointClients.map(fn))
105+
: fn(this.sharedClient);
94106
}
95107

96108
setup(config) {
97-
this.url = `mongodb://${config.host}:${config.port}/?replicaSet=${config.replicasetName}`;
109+
if (config.options.proxies) {
110+
const mainProxy = config.options.proxies[0];
111+
this.url = `mongodb://${mainProxy.host}:${mainProxy.port}/`;
112+
113+
this.failPointClients = config.options.proxies.map(proxy =>
114+
config.newClient(`mongodb://${proxy.host}:${proxy.port}/`)
115+
);
116+
} else {
117+
this.url = config.url();
118+
}
98119

99-
this.sharedClient = config.newClient(this.url);
100-
return this.sharedClient.connect();
120+
this.sharedClient = this.newClient(config);
121+
return this.runForAllClients(client => client.connect());
122+
}
123+
124+
newClient(config, clientOptions) {
125+
return config.newClient(this.url, clientOptions);
101126
}
102127

103128
teardown() {
104-
return this.sharedClient.close();
129+
return this.runForAllClients(client => client.close());
130+
}
131+
132+
enableFailPoint(failPoint) {
133+
return this.runFailPointCmd(client => {
134+
return client.db(this.dbName).executeDbAdminCommand(failPoint);
135+
});
136+
}
137+
138+
disableFailPoint(failPoint) {
139+
return this.runFailPointCmd(client => {
140+
return client.db(this.dbName).executeDbAdminCommand({
141+
configureFailPoint: failPoint.configureFailPoint,
142+
mode: 'off'
143+
});
144+
});
105145
}
106146
}
107147

@@ -123,7 +163,7 @@ describe('Transactions', function() {
123163
return testContext.setup(this.configuration);
124164
});
125165

126-
generateTestSuiteTests(testSuites, testContext);
166+
generateTopologyTests(testSuites, testContext);
127167
});
128168
});
129169

@@ -140,7 +180,7 @@ describe('Transactions', function() {
140180
});
141181

142182
it('should provide a useful error if a Promise is not returned', {
143-
metadata: { requires: { topology: ['replicaset', 'mongos'], mongodb: '>=4.0.x' } },
183+
metadata: { requires: { topology: ['replicaset', 'sharded'], mongodb: '>=4.1.5' } },
144184
test: function(done) {
145185
function fnThatDoesntReturnPromise() {
146186
return false;
@@ -156,27 +196,43 @@ describe('Transactions', function() {
156196
});
157197
});
158198

159-
function generateTestSuiteTests(testSuites, testContext) {
199+
function generateTopologyTests(testSuites, testContext) {
200+
[
201+
{ topology: 'replicaset', minServerVersion: '>=3.7.x' },
202+
{ topology: 'sharded', minServerVersion: '>=4.1.5' }
203+
].forEach(config => {
204+
describe(config.topology, function() {
205+
generateTestSuiteTests(testSuites, testContext, config);
206+
});
207+
});
208+
}
209+
210+
function generateTestSuiteTests(testSuites, testContext, config) {
160211
testSuites.forEach(testSuite => {
161212
const minServerVersion = testSuite.minServerVersion
162213
? `>=${testSuite.minServerVersion}`
163-
: '>=3.7.x';
214+
: config.minServerVersion;
215+
216+
const metadata = {
217+
requires: {
218+
topology: [config.topology],
219+
mongodb: minServerVersion
220+
}
221+
};
164222

165223
describe(testSuite.name, {
166-
metadata: { requires: { topology: ['replicaset', 'mongos'], mongodb: minServerVersion } },
224+
metadata,
167225
test: function() {
168226
beforeEach(() => prepareDatabaseForSuite(testSuite, testContext));
169227
afterEach(() => cleanupAfterSuite(testContext));
170228

171229
testSuite.tests.forEach(testData => {
172-
const maybeSkipIt = testData.skipReason || testSuite.name === 'pin-mongos' ? it.skip : it;
230+
const maybeSkipIt = testData.skipReason ? it.skip : it;
173231
maybeSkipIt(testData.description, function() {
174232
let testPromise = Promise.resolve();
175233

176234
if (testData.failPoint) {
177-
testPromise = testPromise.then(() =>
178-
enableFailPoint(testData.failPoint, testContext)
179-
);
235+
testPromise = testPromise.then(() => testContext.enableFailPoint(testData.failPoint));
180236
}
181237

182238
// run the actual test
@@ -186,11 +242,11 @@ function generateTestSuiteTests(testSuites, testContext) {
186242

187243
if (testData.failPoint) {
188244
testPromise = testPromise.then(() =>
189-
disableFailPoint(testData.failPoint, testContext)
245+
testContext.disableFailPoint(testData.failPoint)
190246
);
191247
}
192248

193-
return testPromise;
249+
return testPromise.then(() => validateOutcome(testData, testContext));
194250
});
195251
});
196252
}
@@ -230,17 +286,6 @@ function cleanupAfterSuite(context) {
230286
}
231287
}
232288

233-
function enableFailPoint(failPoint, testContext) {
234-
return testContext.sharedClient.db(testContext.dbName).executeDbAdminCommand(failPoint);
235-
}
236-
237-
function disableFailPoint(failPoint, testContext) {
238-
return testContext.sharedClient.db(testContext.dbName).executeDbAdminCommand({
239-
configureFailPoint: failPoint.configureFailPoint,
240-
mode: 'off'
241-
});
242-
}
243-
244289
function parseSessionOptions(options) {
245290
const result = Object.assign({}, options);
246291
if (result.defaultTransactionOptions && result.defaultTransactionOptions.readPreference) {
@@ -263,7 +308,7 @@ function runTestSuiteTest(configuration, testData, context) {
263308
clientOptions.autoReconnect = false;
264309
clientOptions.haInterval = 100;
265310

266-
const client = configuration.newClient(context.url, clientOptions);
311+
const client = context.newClient(configuration, clientOptions);
267312
return client.connect().then(client => {
268313
context.testClient = client;
269314
client.on('commandStarted', event => {
@@ -310,6 +355,23 @@ function runTestSuiteTest(configuration, testData, context) {
310355
});
311356
}
312357

358+
function validateOutcome(testData, testContext) {
359+
if (testData.outcome) {
360+
if (testData.outcome.collection) {
361+
// use the client without transactions to verify
362+
return testContext.sharedClient
363+
.db(testContext.dbName)
364+
.collection(testContext.collectionName)
365+
.find({}, { readPreference: 'primary', readConcern: { level: 'local' } })
366+
.toArray()
367+
.then(docs => {
368+
expect(docs).to.eql(testData.outcome.collection.data);
369+
});
370+
}
371+
}
372+
return Promise.resolve();
373+
}
374+
313375
function validateExpectations(commandEvents, testData, testContext, operationContext) {
314376
const session0 = operationContext.session0;
315377
const session1 = operationContext.session1;
@@ -366,20 +428,6 @@ function validateExpectations(commandEvents, testData, testContext, operationCon
366428
expect(actualCommand).to.containSubset(expectedCommand);
367429
});
368430
}
369-
370-
if (testData.outcome) {
371-
if (testData.outcome.collection) {
372-
// use the client without transactions to verify
373-
return testContext.sharedClient
374-
.db(testContext.dbName)
375-
.collection(testContext.collectionName)
376-
.find({}, { readPreference: 'primary', readConcern: { level: 'local' } })
377-
.toArray()
378-
.then(docs => {
379-
expect(docs).to.eql(testData.outcome.collection.data);
380-
});
381-
}
382-
}
383431
}
384432

385433
function linkSessionData(command, context) {

0 commit comments

Comments
 (0)