Skip to content

Commit 5ce3437

Browse files
committed
test(retryable-writes): add test harness for retryable writes
NODE-1105
1 parent 6e86881 commit 5ce3437

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
'use strict';
2+
3+
var fs = require('fs'),
4+
path = require('path'),
5+
expect = require('chai').expect;
6+
7+
let testContext = {};
8+
describe('Retryable Writes', function() {
9+
before(function() {
10+
var configuration = this.configuration;
11+
var MongoClient = configuration.require.MongoClient;
12+
return MongoClient.connect(configuration.url()).then(function(client) {
13+
testContext.client = client;
14+
testContext.db = client.db(configuration.db);
15+
});
16+
});
17+
18+
fs
19+
.readdirSync(path.join(__dirname, 'spec', 'retryable-writes'))
20+
.filter(fileName => fileName.indexOf('.json') !== -1)
21+
.map(fileName => [
22+
path.basename(fileName, '.json'),
23+
JSON.parse(
24+
fs.readFileSync(path.join(path.join(__dirname, 'spec', 'retryable-writes'), fileName))
25+
)
26+
])
27+
.forEach(testFileData => {
28+
const methodName = testFileData[0];
29+
const scenario = testFileData[1];
30+
31+
describe(methodName, function() {
32+
scenario.tests.forEach(test => {
33+
beforeEach(function() {
34+
if (test.failpoint) {
35+
return testContext.db.command({
36+
configureFailPoint: 'onPrimaryTransactionalWrite',
37+
mode: test.failpoint.mode,
38+
data: test.failpoint.data
39+
});
40+
}
41+
});
42+
43+
afterEach(function() {
44+
if (test.failpoint) {
45+
return testContext.db.command({
46+
configureFailPoint: 'onPrimaryTransactionalWrite',
47+
mode: 'off'
48+
});
49+
}
50+
});
51+
52+
it(test.description, {
53+
metadata: {
54+
requires: { topology: ['single'], mongodb: '>=' + scenario.minServerVersion }
55+
},
56+
57+
test: function() {
58+
return executeScenarioTest(scenario, test, this.configuration, testContext);
59+
}
60+
});
61+
});
62+
});
63+
});
64+
});
65+
66+
const convertBulkWriteOperation = op => {
67+
const result = {};
68+
result[op.name] = op.arguments;
69+
return result;
70+
};
71+
72+
function executeScenarioTest(scenario, test, configuration, context) {
73+
var collection = context.db.collection(
74+
'retryable_writes_test_' + scenario.name + '_' + test.operation.name
75+
);
76+
77+
const errorHandler = err => {
78+
if (!err.message.match(/ns not found/)) throw err;
79+
};
80+
81+
return collection
82+
.drop()
83+
.catch(errorHandler)
84+
.then(() => (scenario.data ? collection.insertMany(scenario.data) : Promise.resolve()))
85+
.then(() => {
86+
let args = [],
87+
options = {};
88+
if (test.operation.arguments) {
89+
Object.keys(test.operation.arguments).forEach(arg => {
90+
if (arg === 'requests') {
91+
args.push(test.operation.arguments[arg].map(convertBulkWriteOperation));
92+
} else if (arg === 'upsert') {
93+
options.upsert = test.operation.arguments[arg];
94+
} else if (arg === 'returnDocument') {
95+
const returnDocument = test.operation.arguments[arg];
96+
options.returnOriginal = returnDocument === 'After';
97+
} else {
98+
args.push(test.operation.arguments[arg]);
99+
}
100+
});
101+
102+
if (Object.keys(options).length > 0) args.push(options);
103+
}
104+
105+
let result = collection[test.operation.name].apply(collection, args);
106+
if (test.outcome.error) {
107+
result = result.then(() => expect(false).to.be.true).catch(err => expect(err).to.exist);
108+
} else if (test.outcome.result) {
109+
result = result.then(r => expect(r).to.deep.include(test.outcome.result));
110+
}
111+
112+
return result;
113+
})
114+
.then(() => {
115+
if (test.outcome.collection) {
116+
return collection
117+
.find({})
118+
.toArray()
119+
.then(function(collectionResults) {
120+
expect(collectionResults).to.eql(test.outcome.collection.data);
121+
});
122+
}
123+
});
124+
}

0 commit comments

Comments
 (0)