Skip to content

Commit c3e127a

Browse files
committed
test(txns): refactor test runner to allow for failPoints
1 parent 2d4858a commit c3e127a

File tree

1 file changed

+129
-115
lines changed

1 file changed

+129
-115
lines changed

test/functional/transactions_tests.js

+129-115
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,16 @@ describe('Transactions (spec)', function() {
9292
})
9393
);
9494

95-
after(() => testContext.client.close());
95+
after(() => testContext.sharedClient.close());
9696
before(function() {
9797
// create a shared client for admin tasks
9898
const config = this.configuration;
9999
testContext.url = `mongodb://${config.host}:${config.port}/${testContext.dbName}?replicaSet=${
100100
config.replicasetName
101101
}`;
102102

103-
testContext.client = new MongoClient(testContext.url);
104-
return testContext.client.connect();
103+
testContext.sharedClient = new MongoClient(testContext.url);
104+
return testContext.sharedClient.connect();
105105
});
106106

107107
testSuites.forEach(testSuite => {
@@ -111,14 +111,23 @@ describe('Transactions (spec)', function() {
111111
beforeEach(() => prepareDatabaseForSuite(testSuite, testContext));
112112
afterEach(() => cleanupAfterSuite(testContext));
113113

114-
testSuite.tests.forEach(testData => runTestSuiteTest(testData, testContext));
114+
testSuite.tests.forEach(testData => {
115+
const maybeSkipIt = testData.skipReason ? it.skip : it;
116+
maybeSkipIt(testData.description, function() {
117+
let testPromise = Promise.resolve();
118+
testPromise = testPromise.then(() => runTestSuiteTest(testData, testContext));
119+
120+
return testPromise;
121+
});
122+
});
115123
}
116124
});
117125
});
118126
});
119127

128+
// Test runner helpers
120129
function prepareDatabaseForSuite(suite, context) {
121-
const db = context.client.db();
130+
const db = context.sharedClient.db();
122131
const coll = db.collection(context.collectionName);
123132

124133
return db
@@ -146,126 +155,131 @@ function cleanupAfterSuite(context) {
146155
}
147156

148157
let displayCommands = false;
149-
150158
function runTestSuiteTest(testData, context) {
151-
const maybeSkipIt = testData.skipReason ? it.skip : it;
152-
maybeSkipIt(testData.description, function() {
153-
const commandEvents = [];
154-
const clientOptions = translateClientOptions(
155-
Object.assign({ monitorCommands: true }, testData.clientOptions)
159+
const commandEvents = [];
160+
const clientOptions = translateClientOptions(
161+
Object.assign({ monitorCommands: true }, testData.clientOptions)
162+
);
163+
164+
return MongoClient.connect(context.url, clientOptions).then(client => {
165+
context.testClient = client;
166+
client.on('commandStarted', event => {
167+
if (
168+
event.databaseName === context.dbName ||
169+
['startTransaction', 'commitTransaction', 'abortTransaction'].includes(event.commandName)
170+
) {
171+
commandEvents.push(event);
172+
}
173+
174+
// very useful for debugging
175+
if (displayCommands) {
176+
console.dir(event, { depth: 5 });
177+
}
178+
});
179+
180+
const sessionOptions = Object.assign({}, testData.transactionOptions);
181+
182+
testData.sessionOptions = testData.sessionOptions || {};
183+
const database = client.db();
184+
const session0 = client.startSession(
185+
Object.assign({}, sessionOptions, testData.sessionOptions.session0)
186+
);
187+
const session1 = client.startSession(
188+
Object.assign({}, sessionOptions, testData.sessionOptions.session1)
156189
);
157190

158-
return MongoClient.connect(context.url, clientOptions).then(client => {
159-
context.testClient = client;
160-
client.on('commandStarted', event => {
161-
if (
162-
event.databaseName === context.dbName ||
163-
['startTransaction', 'commitTransaction', 'abortTransaction'].includes(event.commandName)
164-
) {
165-
commandEvents.push(event);
166-
}
191+
// enable to see useful APM debug information at the time of actual test run
192+
// displayCommands = true;
167193

168-
// very useful for debugging
169-
if (displayCommands) {
170-
console.dir(event, { depth: 5 });
171-
}
172-
});
194+
const operationContext = { database, session0, session1 };
173195

174-
const sessionOptions = Object.assign({}, testData.transactionOptions);
196+
let testPromise = Promise.resolve();
197+
return testPromise
198+
.then(() => testOperations(client, testData, operationContext))
199+
.catch(err => {
200+
// If the driver throws an exception / returns an error while executing this series
201+
// of operations, store the error message.
202+
throw err;
203+
})
204+
.then(() => {
205+
session0.endSession();
206+
session1.endSession();
175207

176-
testData.sessionOptions = testData.sessionOptions || {};
177-
const database = client.db();
178-
const session0 = client.startSession(
179-
Object.assign({}, sessionOptions, testData.sessionOptions.session0)
180-
);
181-
const session1 = client.startSession(
182-
Object.assign({}, sessionOptions, testData.sessionOptions.session1)
183-
);
208+
return validateExpectations(commandEvents, testData, context, operationContext);
209+
});
210+
});
211+
}
184212

185-
// enable to see useful APM debug information at the time of actual test run
186-
// displayCommands = true;
213+
function validateExpectations(commandEvents, testData, testContext, operationContext) {
214+
const session0 = operationContext.session0;
215+
const session1 = operationContext.session1;
216+
217+
if (
218+
testData.expectations &&
219+
Array.isArray(testData.expectations) &&
220+
testData.expectations.length > 0
221+
) {
222+
const actualEvents = normalizeCommandShapes(commandEvents);
223+
const rawExpectedEvents = testData.expectations.map(x =>
224+
linkSessionData(x.command_started_event, { session0, session1 })
225+
);
187226

188-
let testPromise = Promise.resolve();
189-
return testPromise
190-
.then(() => testOperations(client, testData, { database, session0, session1 }))
191-
.catch(err => {
192-
// If the driver throws an exception / returns an error while executing this series
193-
// of operations, store the error message.
194-
throw err;
195-
})
196-
.then(() => {
197-
session0.endSession();
198-
session1.endSession();
199-
200-
if (
201-
testData.expectations &&
202-
Array.isArray(testData.expectations) &&
203-
testData.expectations.length > 0
204-
) {
205-
const actualEvents = normalizeCommandShapes(commandEvents);
206-
const rawExpectedEvents = testData.expectations.map(x =>
207-
linkSessionData(x.command_started_event, { session0, session1 })
208-
);
209-
210-
const expectedEventPlaceholders = rawExpectedEvents.map(event =>
211-
findPlaceholders(event.command)
212-
);
213-
214-
const expectedEvents = normalizeCommandShapes(rawExpectedEvents);
215-
expect(actualEvents).to.have.length(expectedEvents.length);
216-
217-
expectedEvents.forEach((expected, idx) => {
218-
const actual = actualEvents[idx];
219-
const placeHolders = expectedEventPlaceholders[idx]; // eslint-disable-line
220-
221-
expect(actual.commandName).to.equal(expected.commandName);
222-
expect(actual.databaseName).to.equal(expected.databaseName);
223-
224-
const actualCommand = actual.command;
225-
const expectedCommand = expected.command;
226-
227-
// handle validation of placeholder values
228-
// placeHolders.forEach(placeholder => {
229-
// const parsedActual = EJSON.parse(JSON.stringify(actualCommand), {
230-
// relaxed: true
231-
// });
232-
233-
// if (placeholder.type === null) {
234-
// expect(parsedActual).to.not.have.all.nested.property(placeholder.path);
235-
// } else if (placeholder.type === 'string') {
236-
// expect(parsedActual).nested.property(placeholder.path).to.exist;
237-
// expect(parsedActual)
238-
// .nested.property(placeholder.path)
239-
// .to.have.length.greaterThan(0);
240-
// } else if (placeholder.type === 'number') {
241-
// expect(parsedActual).nested.property(placeholder.path).to.exist;
242-
// expect(parsedActual)
243-
// .nested.property(placeholder.path)
244-
// .to.be.greaterThan(0);
245-
// }
246-
// });
247-
248-
// compare the command
249-
expect(actualCommand).to.containSubset(expectedCommand);
250-
});
251-
}
227+
const expectedEventPlaceholders = rawExpectedEvents.map(event =>
228+
findPlaceholders(event.command)
229+
);
252230

253-
if (testData.outcome) {
254-
if (testData.outcome.collection) {
255-
// use the client without transactions to verify
256-
return context.client
257-
.db()
258-
.collection(context.collectionName)
259-
.find({})
260-
.toArray()
261-
.then(docs => {
262-
expect(docs).to.eql(testData.outcome.collection.data);
263-
});
264-
}
265-
}
266-
});
231+
const expectedEvents = normalizeCommandShapes(rawExpectedEvents);
232+
expect(actualEvents).to.have.length(expectedEvents.length);
233+
234+
expectedEvents.forEach((expected, idx) => {
235+
const actual = actualEvents[idx];
236+
const placeHolders = expectedEventPlaceholders[idx]; // eslint-disable-line
237+
238+
expect(actual.commandName).to.equal(expected.commandName);
239+
expect(actual.databaseName).to.equal(expected.databaseName);
240+
241+
const actualCommand = actual.command;
242+
const expectedCommand = expected.command;
243+
244+
// handle validation of placeholder values
245+
// placeHolders.forEach(placeholder => {
246+
// const parsedActual = EJSON.parse(JSON.stringify(actualCommand), {
247+
// relaxed: true
248+
// });
249+
250+
// if (placeholder.type === null) {
251+
// expect(parsedActual).to.not.have.all.nested.property(placeholder.path);
252+
// } else if (placeholder.type === 'string') {
253+
// expect(parsedActual).nested.property(placeholder.path).to.exist;
254+
// expect(parsedActual)
255+
// .nested.property(placeholder.path)
256+
// .to.have.length.greaterThan(0);
257+
// } else if (placeholder.type === 'number') {
258+
// expect(parsedActual).nested.property(placeholder.path).to.exist;
259+
// expect(parsedActual)
260+
// .nested.property(placeholder.path)
261+
// .to.be.greaterThan(0);
262+
// }
263+
// });
264+
265+
// compare the command
266+
expect(actualCommand).to.containSubset(expectedCommand);
267267
});
268-
});
268+
}
269+
270+
if (testData.outcome) {
271+
if (testData.outcome.collection) {
272+
// use the client without transactions to verify
273+
return testContext.sharedClient
274+
.db()
275+
.collection(testContext.collectionName)
276+
.find({})
277+
.toArray()
278+
.then(docs => {
279+
expect(docs).to.eql(testData.outcome.collection.data);
280+
});
281+
}
282+
}
269283
}
270284

271285
function linkSessionData(command, context) {

0 commit comments

Comments
 (0)