Skip to content

Commit de9fd7f

Browse files
authored
chore: add failpoint interface (#3181)
1 parent d2897ab commit de9fd7f

File tree

1 file changed

+68
-63
lines changed

1 file changed

+68
-63
lines changed

test/tools/utils.js renamed to test/tools/utils.ts

Lines changed: 68 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
1-
'use strict';
1+
import { EJSON } from 'bson';
2+
import { expect } from 'chai';
3+
import util from 'util';
24

3-
const { Logger } = require('../../src/logger');
4-
const { deprecateOptions } = require('../../src/utils');
5-
const util = require('util');
6-
const chai = require('chai');
5+
import { Logger } from '../../src/logger';
6+
import { deprecateOptions, DeprecateOptionsConfig } from '../../src/utils';
77

8-
const expect = chai.expect;
9-
const sinonChai = require('sinon-chai');
10-
const { EJSON } = require('bson');
11-
12-
chai.use(sinonChai);
13-
14-
function makeTestFunction(config) {
15-
const fn = options => {
8+
export function makeTestFunction(config: DeprecateOptionsConfig) {
9+
const fn = (options: any) => {
1610
if (options) options = null;
1711
};
1812
return deprecateOptions(config, fn);
1913
}
2014

21-
function ensureCalledWith(stub, args) {
22-
args.forEach(m => expect(stub).to.have.been.calledWith(m));
15+
export function ensureCalledWith(stub: any, args: any[]) {
16+
args.forEach((m: any) => expect(stub).to.have.been.calledWith(m));
2317
}
2418

2519
// creation of class with a logger
26-
function ClassWithLogger() {
20+
export function ClassWithLogger() {
2721
this.logger = new Logger('ClassWithLogger');
2822
}
2923

@@ -38,7 +32,9 @@ ClassWithLogger.prototype.getLogger = function () {
3832
};
3933

4034
// creation of class without a logger
41-
function ClassWithoutLogger() {}
35+
export function ClassWithoutLogger() {
36+
// empty function for class
37+
}
4238

4339
ClassWithoutLogger.prototype.f = makeTestFunction({
4440
name: 'f',
@@ -47,7 +43,9 @@ ClassWithoutLogger.prototype.f = makeTestFunction({
4743
});
4844

4945
// creation of class where getLogger returns undefined
50-
function ClassWithUndefinedLogger() {}
46+
export function ClassWithUndefinedLogger() {
47+
// empty function for class
48+
}
5149

5250
ClassWithUndefinedLogger.prototype.f = makeTestFunction({
5351
name: 'f',
@@ -59,18 +57,24 @@ ClassWithUndefinedLogger.prototype.getLogger = function () {
5957
return undefined;
6058
};
6159

62-
class EventCollector {
63-
constructor(obj, events, options) {
60+
export class EventCollector {
61+
private _events: Record<string, any[]>;
62+
private _timeout: number;
63+
constructor(
64+
obj: { on: (arg0: any, arg1: (event: any) => number) => void },
65+
events: any[],
66+
options: { timeout: number }
67+
) {
6468
this._events = Object.create(null);
6569
this._timeout = options ? options.timeout : 5000;
6670

67-
events.forEach(eventName => {
71+
events.forEach((eventName: string | number) => {
6872
this._events[eventName] = [];
69-
obj.on(eventName, event => this._events[eventName].push(event));
73+
obj.on(eventName, (event: any) => this._events[eventName].push(event));
7074
});
7175
}
7276

73-
waitForEvent(eventName, count, callback) {
77+
waitForEvent(eventName: any, count: number, callback: any) {
7478
if (typeof count === 'function') {
7579
callback = count;
7680
count = 1;
@@ -82,23 +86,20 @@ class EventCollector {
8286
/**
8387
* Will only return one event at a time from the front of the list
8488
* Useful for iterating over the events in the order they occurred
85-
*
86-
* @param {string} eventName
87-
* @returns {Promise<Record<string, any>>}
8889
*/
89-
waitAndShiftEvent(eventName) {
90-
return new Promise((resolve, reject) => {
90+
waitAndShiftEvent(eventName: string): Promise<Record<string, any>> {
91+
return new Promise<Record<string, any>>((resolve, reject) => {
9192
if (this._events[eventName].length > 0) {
9293
return resolve(this._events[eventName].shift());
9394
}
94-
this.waitForEventImpl(this, Date.now(), eventName, 1, error => {
95+
this.waitForEventImpl(this, Date.now(), eventName, 1, (error: any) => {
9596
if (error) return reject(error);
9697
resolve(this._events[eventName].shift());
9798
});
9899
});
99100
}
100101

101-
reset(eventName) {
102+
reset(eventName: string) {
102103
if (eventName == null) {
103104
Object.keys(this._events).forEach(eventName => {
104105
this._events[eventName] = [];
@@ -114,7 +115,13 @@ class EventCollector {
114115
this._events[eventName] = [];
115116
}
116117

117-
waitForEventImpl(collector, start, eventName, count, callback) {
118+
waitForEventImpl(
119+
collector: this,
120+
start: number,
121+
eventName: string | number,
122+
count: number,
123+
callback: (error?: Error, events?: any[]) => void
124+
) {
118125
const events = collector._events[eventName];
119126
if (events.length >= count) {
120127
return callback(undefined, events);
@@ -128,7 +135,7 @@ class EventCollector {
128135
}
129136
}
130137

131-
function getSymbolFrom(target, symbolName, assertExists = true) {
138+
export function getSymbolFrom(target: any, symbolName: any, assertExists = true) {
132139
const symbol = Object.getOwnPropertySymbols(target).filter(
133140
s => s.toString() === `Symbol(${symbolName})`
134141
)[0];
@@ -140,7 +147,7 @@ function getSymbolFrom(target, symbolName, assertExists = true) {
140147
return symbol;
141148
}
142149

143-
function getEnvironmentalOptions() {
150+
export function getEnvironmentalOptions() {
144151
const options = {};
145152
if (process.env.MONGODB_API_VERSION) {
146153
Object.assign(options, {
@@ -160,7 +167,7 @@ function getEnvironmentalOptions() {
160167
return options;
161168
}
162169

163-
function shouldRunServerlessTest(testRequirement, isServerless) {
170+
export function shouldRunServerlessTest(testRequirement: any, isServerless: any) {
164171
if (!testRequirement) return true;
165172
switch (testRequirement) {
166173
case 'forbid':
@@ -182,11 +189,11 @@ function shouldRunServerlessTest(testRequirement, isServerless) {
182189
* Attempts to use EJSON (to make type information obvious)
183190
* falls back to util.inspect if there's an error (circular reference)
184191
*/
185-
function ejson(strings, ...values) {
192+
export function ejson(strings: any[], ...values: any[]) {
186193
const stringParts = [strings[0]];
187194
for (const [idx, value] of values.entries()) {
188195
if (typeof value === 'object') {
189-
let stringifiedObject;
196+
let stringifiedObject: string;
190197
try {
191198
stringifiedObject = EJSON.stringify(value, { relaxed: false });
192199
} catch (error) {
@@ -208,25 +215,24 @@ function ejson(strings, ...values) {
208215

209216
/**
210217
* Run an async function after some set timeout
211-
* @param {() => Promise<void>} fn - function to run
212-
* @param {number} ms - timeout in MS
213-
* @returns {Promise<void>}
218+
* @param fn - function to run
219+
* @param ms - timeout in MS
214220
*/
215-
const runLater = (fn, ms) => {
216-
return new Promise((resolve, reject) => {
221+
export const runLater = (fn: () => Promise<void>, ms: number) => {
222+
return new Promise<void>((resolve, reject) => {
217223
setTimeout(() => fn().then(resolve).catch(reject), ms);
218224
});
219225
};
220226

221-
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
227+
export const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
222228

223229
/**
224230
* If you are using sinon fake timers, it can end up blocking queued IO from running
225231
* awaiting a nextTick call will allow the event loop to process Networking/FS callbacks
226232
*/
227-
const processTick = () => new Promise(resolve => process.nextTick(resolve));
233+
export const processTick = () => new Promise(resolve => process.nextTick(resolve));
228234

229-
function getIndicesOfAuthInUrl(connectionString) {
235+
export function getIndicesOfAuthInUrl(connectionString: string | string[]) {
230236
const doubleSlashIndex = connectionString.indexOf('//');
231237
const atIndex = connectionString.indexOf('@');
232238

@@ -240,7 +246,7 @@ function getIndicesOfAuthInUrl(connectionString) {
240246
};
241247
}
242248

243-
function removeAuthFromConnectionString(connectionString) {
249+
export function removeAuthFromConnectionString(connectionString: string) {
244250
const indices = getIndicesOfAuthInUrl(connectionString);
245251
if (!indices) {
246252
return connectionString;
@@ -255,7 +261,7 @@ function removeAuthFromConnectionString(connectionString) {
255261
return connectionString.slice(0, start) + connectionString.slice(end + 1);
256262
}
257263

258-
function extractAuthFromConnectionString(connectionString) {
264+
export function extractAuthFromConnectionString(connectionString: string | any[]) {
259265
const indices = getIndicesOfAuthInUrl(connectionString);
260266
if (!indices) {
261267
return null;
@@ -264,20 +270,19 @@ function extractAuthFromConnectionString(connectionString) {
264270
return connectionString.slice(indices.start, indices.end);
265271
}
266272

267-
module.exports = {
268-
processTick,
269-
sleep,
270-
runLater,
271-
ejson,
272-
EventCollector,
273-
makeTestFunction,
274-
ensureCalledWith,
275-
ClassWithLogger,
276-
ClassWithoutLogger,
277-
ClassWithUndefinedLogger,
278-
getSymbolFrom,
279-
getEnvironmentalOptions,
280-
shouldRunServerlessTest,
281-
removeAuthFromConnectionString,
282-
extractAuthFromConnectionString
283-
};
273+
export interface FailPoint {
274+
configureFailPoint: 'failCommand';
275+
mode: { activationProbability: number } | { times: number } | 'alwaysOn' | 'off';
276+
data: {
277+
failCommands: string[];
278+
errorCode?: number;
279+
closeConnection?: boolean;
280+
blockConnection?: boolean;
281+
blockTimeMS?: number;
282+
writeConcernError?: { code: number; errmsg: string };
283+
threadName?: string;
284+
failInternalCommands?: boolean;
285+
errorLabels?: string[];
286+
appName?: string;
287+
};
288+
}

0 commit comments

Comments
 (0)