Skip to content

Commit aa724f3

Browse files
temp commit
1 parent 1540db0 commit aa724f3

File tree

196 files changed

+33768
-9389
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

196 files changed

+33768
-9389
lines changed
Lines changed: 1 addition & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,8 @@
1-
import { expect } from 'chai';
21
import * as path from 'path';
32

4-
import type { Collection, Db, MongoClient } from '../../mongodb';
53
import { loadSpecTests } from '../../spec';
6-
import { legacyRunOnToRunOnRequirement } from '../../tools/spec-runner';
74
import { runUnifiedSuite } from '../../tools/unified-spec-runner/runner';
8-
import { isAnyRequirementSatisfied } from '../../tools/unified-spec-runner/unified-utils';
95

10-
interface RetryableWriteTestContext {
11-
client?: MongoClient;
12-
db?: Db;
13-
collection?: Collection;
14-
failPointName?: any;
15-
}
16-
17-
describe('Legacy Retryable Writes Specs', function () {
18-
let ctx: RetryableWriteTestContext = {};
19-
20-
const retryableWrites = loadSpecTests('retryable-writes', 'legacy');
21-
22-
for (const suite of retryableWrites) {
23-
describe(suite.name, function () {
24-
beforeEach(async function () {
25-
let utilClient: MongoClient;
26-
if (this.configuration.isLoadBalanced) {
27-
// The util client can always point at the single mongos LB frontend.
28-
utilClient = this.configuration.newClient(this.configuration.singleMongosLoadBalancerUri);
29-
} else {
30-
utilClient = this.configuration.newClient();
31-
}
32-
33-
await utilClient.connect();
34-
35-
const allRequirements = suite.runOn.map(legacyRunOnToRunOnRequirement);
36-
37-
const someRequirementMet =
38-
!allRequirements.length ||
39-
(await isAnyRequirementSatisfied(this.currentTest.ctx, allRequirements, utilClient));
40-
41-
await utilClient.close();
42-
43-
if (!someRequirementMet) this.skip();
44-
});
45-
46-
beforeEach(async function () {
47-
// Step 1: Test Setup. Includes a lot of boilerplate stuff
48-
// like creating a client, dropping and refilling data collections,
49-
// and enabling failpoints
50-
const { spec } = this.currentTest;
51-
await executeScenarioSetup(suite, spec, this.configuration, ctx);
52-
});
53-
54-
afterEach(async function () {
55-
// Step 3: Test Teardown. Turn off failpoints, and close client
56-
if (!ctx.db || !ctx.client) {
57-
return;
58-
}
59-
60-
if (ctx.failPointName) {
61-
await turnOffFailPoint(ctx.client, ctx.failPointName);
62-
}
63-
await ctx.client.close();
64-
ctx = {}; // reset context
65-
});
66-
67-
for (const spec of suite.tests) {
68-
// Step 2: Run the test
69-
const mochaTest = it(spec.description, async () => await executeScenarioTest(spec, ctx));
70-
71-
// A pattern we don't need to repeat for unified tests
72-
// In order to give the beforeEach hook access to the
73-
// spec test so it can be responsible for skipping it
74-
// and executeScenarioSetup
75-
mochaTest.spec = spec;
76-
}
77-
});
78-
}
79-
});
80-
81-
async function executeScenarioSetup(scenario, test, config, ctx) {
82-
const url = config.url();
83-
const options = {
84-
...test.clientOptions,
85-
heartbeatFrequencyMS: 100,
86-
monitorCommands: true,
87-
minPoolSize: 10
88-
};
89-
90-
ctx.failPointName = test.failPoint && test.failPoint.configureFailPoint;
91-
92-
const client = config.newClient(url, options);
93-
await client.connect();
94-
95-
ctx.client = client;
96-
ctx.db = client.db(config.db);
97-
ctx.collection = ctx.db.collection(`retryable_writes_test_${config.name}_${test.operation.name}`);
98-
99-
try {
100-
await ctx.collection.drop();
101-
} catch (error) {
102-
if (!error.message.match(/ns not found/)) {
103-
throw error;
104-
}
105-
}
106-
107-
if (Array.isArray(scenario.data) && scenario.data.length) {
108-
await ctx.collection.insertMany(scenario.data);
109-
}
110-
111-
if (test.failPoint) {
112-
await ctx.client.db('admin').command(test.failPoint);
113-
}
114-
}
115-
116-
async function executeScenarioTest(test, ctx: RetryableWriteTestContext) {
117-
const args = generateArguments(test);
118-
119-
// In case the spec files or our API changes
120-
expect(ctx.collection).to.have.property(test.operation.name).that.is.a('function');
121-
122-
// TODO(NODE-4033): Collect command started events and assert txn number existence or omission
123-
// have to add logic to handle bulkWrites which emit multiple command started events
124-
const resultOrError = await ctx.collection[test.operation.name](...args).catch(error => error);
125-
126-
const outcome = test.outcome && test.outcome.result;
127-
const errorLabelsContain = outcome && outcome.errorLabelsContain;
128-
const errorLabelsOmit = outcome && outcome.errorLabelsOmit;
129-
const hasResult = outcome && !errorLabelsContain && !errorLabelsOmit;
130-
if (test.outcome.error) {
131-
const thrownError = resultOrError;
132-
expect(thrownError, `${test.operation.name} was supposed to fail but did not!`).to.exist;
133-
expect(thrownError).to.have.property('message');
134-
135-
if (hasResult) {
136-
expect(thrownError.result).to.matchMongoSpec(test.outcome.result);
137-
}
138-
139-
if (errorLabelsContain) {
140-
expect(thrownError.errorLabels).to.include.members(errorLabelsContain);
141-
}
142-
143-
if (errorLabelsOmit) {
144-
for (const label of errorLabelsOmit) {
145-
expect(thrownError.errorLabels).to.not.contain(label);
146-
}
147-
}
148-
} else if (test.outcome.result) {
149-
expect(resultOrError, resultOrError.stack).to.not.be.instanceOf(Error);
150-
const result = resultOrError;
151-
const expected = test.outcome.result;
152-
153-
const actual = result.value ?? result;
154-
// Some of our result classes contain the optional 'acknowledged' property which is
155-
// not part of the test expectations.
156-
for (const property in expected) {
157-
expect(actual).to.have.deep.property(property, expected[property]);
158-
}
159-
}
160-
161-
if (test.outcome.collection) {
162-
const collectionResults = await ctx.collection.find({}).toArray();
163-
expect(collectionResults).to.deep.equal(test.outcome.collection.data);
164-
}
165-
}
166-
167-
// Helper Functions
168-
169-
/** Transforms the arguments from a test into actual arguments for our function calls */
170-
function generateArguments(test) {
171-
const args = [];
172-
173-
if (test.operation.arguments) {
174-
const options: Record<string, any> = {};
175-
for (const arg of Object.keys(test.operation.arguments)) {
176-
if (arg === 'requests') {
177-
/** Transforms a request arg into a bulk write operation */
178-
args.push(
179-
test.operation.arguments[arg].map(({ name, arguments: args }) => ({ [name]: args }))
180-
);
181-
} else if (arg === 'upsert') {
182-
options.upsert = test.operation.arguments[arg];
183-
} else if (arg === 'returnDocument') {
184-
options.returnDocument = test.operation.arguments[arg].toLowerCase();
185-
} else {
186-
args.push(test.operation.arguments[arg]);
187-
}
188-
}
189-
190-
if (Object.keys(options).length > 0) {
191-
args.push(options);
192-
}
193-
}
194-
195-
return args;
196-
}
197-
198-
/** Runs a command that turns off a fail point */
199-
async function turnOffFailPoint(client, name) {
200-
return await client.db('admin').command({
201-
configureFailPoint: name,
202-
mode: 'off'
203-
});
204-
}
205-
206-
describe('Retryable Writes (unified)', function () {
6+
describe.only('Retryable Writes (unified)', function () {
2077
runUnifiedSuite(loadSpecTests(path.join('retryable-writes', 'unified')));
2088
});

0 commit comments

Comments
 (0)