SERVER-99572: Cover jstests with custom eslint rules (#32277)

Co-authored-by: Serhii Lysenko <serhiilysenko@mongodb.com>
Co-authored-by: Zack Winter <zack.winter@mongodb.com>
Co-authored-by: romanskas <30618745+romanskas@users.noreply.github.com>
GitOrigin-RevId: 7f9fb5e323eb4c87de26ed6756f44b6cdec48305
This commit is contained in:
Serhii Lysenko 2025-02-18 12:40:55 +00:00 committed by MongoDB Bot
parent 2f2816982b
commit 55f2df1754
9 changed files with 424 additions and 266 deletions

View File

@ -1,4 +1,5 @@
load("@npm//:defs.bzl", "npm_link_all_packages")
load("@aspect_rules_js//npm:defs.bzl", "npm_link_package")
load("//bazel/install_rules:install_rules.bzl", "mongo_install")
load("//bazel/toolchains:mongo_toolchain.bzl", "setup_mongo_toolchain_aliases")
load("//bazel/config:render_template.bzl", "render_template")
@ -19,13 +20,19 @@ exports_files([
npm_link_all_packages(name = "node_modules")
npm_link_package(
name = "node_modules/eslint-plugin-mongodb",
src = "//buildscripts/eslint-plugin-mongodb:npm_package",
)
js_library(
name = "eslintrc",
srcs = ["eslint.config.mjs"],
deps = [
":node_modules/@eslint/eslintrc",
":node_modules/@eslint/js",
":node_modules/eslint-plugin-mongodb",
":node_modules/globals",
"//:node_modules/@eslint/eslintrc",
],
)

View File

@ -0,0 +1,13 @@
load("@aspect_rules_js//npm:defs.bzl", "npm_package")
npm_package(
name = "npm_package",
srcs = [
"package.json",
"plugin.js",
"rules/no-print-fn.js",
"rules/no-tojson-fn.js",
],
package = "eslint-plugin-mongodb",
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,7 @@
{
"name": "eslint-plugin-mongodb",
"version": "1.0.0",
"private": true,
"main": "plugin.js",
"type": "module"
}

View File

@ -0,0 +1,11 @@
// plugin.js
import {default as no_print} from "./rules/no-print-fn.js";
import {default as no_tojson} from "./rules/no-tojson-fn.js";
export default {
rules: {
"no-print-fn": no_print,
"no-tojson-fn": no_tojson,
},
};

View File

@ -0,0 +1,35 @@
const stopList = [
"print",
"printjson",
"printjsononeline",
];
export default {
meta: {
type: "problem",
docs: {
description: "Ensure no direct calls to print* functions",
},
fixable: "code",
},
create(context) {
return {
CallExpression: function(node) {
if (node.callee.type == "Identifier" &&
stopList.some(fn => fn == node.callee.name)) {
context.report(
{
node,
message: `Direct use of '${
node.callee
.name}()'. Consider using jsTest.log.info() instead or disable mongodb/no-print-fn rule when necessary, e.g., '// eslint-disable-next-line mongodb/no-print-fn'
More about rules configuration: https://eslint.org/docs/latest/use/configure/rules`,
});
}
}
};
}
};

View File

@ -0,0 +1,34 @@
const stopList = [
"tojson",
"tojsononeline",
];
export default {
meta: {
type: "problem",
docs: {
description: "Ensure no direct calls to tojson* functions",
},
fixable: "code",
},
create(context) {
return {
CallExpression: function(node) {
if (node.callee.type == "Identifier" &&
stopList.some(fn => fn == node.callee.name)) {
context.report(
{
node,
message: `Direct use of '${
node.callee
.name}()'. Consider using jsTest.log.info() instead or disable mongodb/no-tojson-fn rule when necessary, e.g., '// eslint-disable-next-line mongodb/no-print-fn'
More about rules configuration: https://eslint.org/docs/latest/use/configure/rules`,
});
}
}
};
}
};

View File

@ -1,9 +1,10 @@
import globals from "globals";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {FlatCompat} from "@eslint/eslintrc";
import eslint from "@eslint/js";
import js from "@eslint/js";
import { FlatCompat } from "@eslint/eslintrc";
import {default as mongodb_plugin} from "eslint-plugin-mongodb";
import globals from "globals";
import path from "node:path";
import {fileURLToPath} from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
@ -13,253 +14,306 @@ const compat = new FlatCompat({
allConfig: js.configs.all
});
export default [{
ignores: ["src/mongo/gotools/*", "**/*.tpl.js", "jstests/third_party/**/*.js"],
}, ...compat.extends("eslint:recommended"), {
languageOptions: {
globals: {
...globals.mongo,
TestData: true,
WriteError: true,
WriteCommandError: true,
BulkWriteError: true,
DB: true,
DBCollection: true,
DBQuery: true,
DBExplainQuery: true,
DBCommandCursor: true,
MongoBridge: true,
MongoURI: true,
WriteConcern: true,
SessionOptions: true,
CollInfos: true,
CountDownLatch: true,
BSONAwareMap: true,
latestFCV: true,
lastLTSFCV: true,
lastContinuousFCV: true,
checkFCV: true,
isFCVEqual: true,
binVersionToFCV: true,
numVersionsSinceLastLTS: true,
getFCVConstants: true,
removeFCVDocument: true,
targetFCV: true,
AssertionError: true,
assert: true,
doassert: true,
authutil: true,
tojson: true,
tojsononeline: true,
tostrictjson: true,
tojsonObject: true,
toEJSON: true,
print: true,
printjson: true,
printjsononeline: true,
jsTest: true,
jsTestLog: true,
jsonTestLog: true,
ErrorCodes: true,
ErrorCodeStrings: true,
checkProgram: true,
Random: true,
checkLog: true,
sleep: true,
resetDbpath: true,
copyDbpath: true,
jsTestName: true,
startParallelShell: true,
buildInfo: true,
getBuildInfo: true,
jsTestOptions: true,
printShardingStatus: true,
_getErrorWithCode: true,
isNetworkError: true,
__magicNoPrint: true,
computeSHA256Block: true,
emit: true,
_awaitRSHostViaRSMonitor: true,
convertShardKeyToHashed: true,
benchRun: true,
benchRunSync: true,
gc: true,
DataConsistencyChecker: true,
isNumber: true,
isObject: true,
isString: true,
_createSecurityToken: true,
_createTenantToken: true,
_isAddressSanitizerActive: true,
_isLeakSanitizerActive: true,
_isThreadSanitizerActive: true,
_isUndefinedBehaviorSanitizerActive: true,
_isSpiderMonkeyDebugEnabled: true,
_optimizationsEnabled: true,
allocatePort: true,
allocatePorts: true,
resetAllocatedPorts: true,
bsonObjToArray: true,
_writeTestPipeObjects: true,
_writeTestPipe: true,
_writeTestPipeBsonFile: true,
_readTestPipes: true,
runFeatureFlagMultiversionTest: true,
isRetryableError: true,
numberDecimalsAlmostEqual: true,
numberDecimalsEqual: true,
debug: true,
bsonsize: true,
_DelegatingDriverSession: true,
_DummyDriverSession: true,
_ServerSession: true,
sortDoc: true,
executeNoThrowNetworkError: true,
_readDumpFile: true,
_openGoldenData: true,
_writeGoldenData: true,
_threadInject: true,
port: true,
_buildBsonObj: true,
convertTrafficRecordingToBSON: true,
_setShellFailPoint: true,
shellHelper: true,
_srand: true,
_shouldUseImplicitSessions: true,
testingReplication: true,
myPort: true,
retryOnNetworkError: true,
getJSHeapLimitMB: true,
_getEnv: true,
indentStr: true,
_forgetReplSet: true,
_fnvHashToHexString: true,
_resultSetsEqualUnordered: true,
getStringWidth: true,
_compareStringsWithCollation: true,
eventResumeTokenType: true,
highWaterMarkResumeTokenType: true,
export default [
...compat
.extends("eslint:recommended"),
{
ignores: ["src/mongo/gotools/*", "**/*.tpl.js", "jstests/third_party/**/*.js"],
},
{
languageOptions: {
globals: {
...globals.mongo,
TestData: true,
WriteError: true,
WriteCommandError: true,
BulkWriteError: true,
DB: true,
DBCollection: true,
DBQuery: true,
DBExplainQuery: true,
DBCommandCursor: true,
MongoBridge: true,
MongoURI: true,
WriteConcern: true,
SessionOptions: true,
CollInfos: true,
CountDownLatch: true,
BSONAwareMap: true,
latestFCV: true,
lastLTSFCV: true,
lastContinuousFCV: true,
checkFCV: true,
isFCVEqual: true,
binVersionToFCV: true,
numVersionsSinceLastLTS: true,
getFCVConstants: true,
removeFCVDocument: true,
targetFCV: true,
AssertionError: true,
assert: true,
doassert: true,
authutil: true,
tojson: true,
tojsononeline: true,
tostrictjson: true,
tojsonObject: true,
toEJSON: true,
print: true,
printjson: true,
printjsononeline: true,
jsTest: true,
jsTestLog: true,
jsonTestLog: true,
ErrorCodes: true,
ErrorCodeStrings: true,
checkProgram: true,
Random: true,
checkLog: true,
sleep: true,
resetDbpath: true,
copyDbpath: true,
jsTestName: true,
startParallelShell: true,
buildInfo: true,
getBuildInfo: true,
jsTestOptions: true,
printShardingStatus: true,
_getErrorWithCode: true,
isNetworkError: true,
__magicNoPrint: true,
computeSHA256Block: true,
emit: true,
_awaitRSHostViaRSMonitor: true,
convertShardKeyToHashed: true,
benchRun: true,
benchRunSync: true,
gc: true,
DataConsistencyChecker: true,
isNumber: true,
isObject: true,
isString: true,
_createSecurityToken: true,
_createTenantToken: true,
_isAddressSanitizerActive: true,
_isLeakSanitizerActive: true,
_isThreadSanitizerActive: true,
_isUndefinedBehaviorSanitizerActive: true,
_isSpiderMonkeyDebugEnabled: true,
_optimizationsEnabled: true,
allocatePort: true,
allocatePorts: true,
resetAllocatedPorts: true,
bsonObjToArray: true,
_writeTestPipeObjects: true,
_writeTestPipe: true,
_writeTestPipeBsonFile: true,
_readTestPipes: true,
runFeatureFlagMultiversionTest: true,
isRetryableError: true,
numberDecimalsAlmostEqual: true,
numberDecimalsEqual: true,
debug: true,
bsonsize: true,
_DelegatingDriverSession: true,
_DummyDriverSession: true,
_ServerSession: true,
sortDoc: true,
executeNoThrowNetworkError: true,
_readDumpFile: true,
_openGoldenData: true,
_writeGoldenData: true,
_threadInject: true,
port: true,
_buildBsonObj: true,
convertTrafficRecordingToBSON: true,
_setShellFailPoint: true,
shellHelper: true,
_srand: true,
_shouldUseImplicitSessions: true,
testingReplication: true,
myPort: true,
retryOnNetworkError: true,
getJSHeapLimitMB: true,
_getEnv: true,
indentStr: true,
_forgetReplSet: true,
_fnvHashToHexString: true,
_resultSetsEqualUnordered: true,
getStringWidth: true,
_compareStringsWithCollation: true,
eventResumeTokenType: true,
highWaterMarkResumeTokenType: true,
// likely could be replaced with `path`
_copyFileRange: true,
appendFile: true,
copyFile: true,
writeFile: true,
fileExists: true,
pathExists: true,
umask: true,
getFileMode: true,
copyDir: true,
// likely could be replaced with `path`
_copyFileRange: true,
appendFile: true,
copyFile: true,
writeFile: true,
fileExists: true,
pathExists: true,
umask: true,
getFileMode: true,
copyDir: true,
// likely could be replaced with `child_process`
MongoRunner: true,
run: true,
runProgram: true,
runMongoProgram: true,
runNonMongoProgram: true,
runNonMongoProgramQuietly: true,
_runMongoProgram: true,
_startMongoProgram: true,
startMongoProgram: true,
_stopMongoProgram: true,
stopMongoProgramByPid: true,
clearRawMongoProgramOutput: true,
rawMongoProgramOutput: true,
waitProgram: true,
waitMongoProgram: true,
_runningMongoChildProcessIds: true,
startMongoProgramNoConnect: true,
// likely could be replaced with `child_process`
MongoRunner: true,
run: true,
runProgram: true,
runMongoProgram: true,
runNonMongoProgram: true,
runNonMongoProgramQuietly: true,
_runMongoProgram: true,
_startMongoProgram: true,
startMongoProgram: true,
_stopMongoProgram: true,
stopMongoProgramByPid: true,
clearRawMongoProgramOutput: true,
rawMongoProgramOutput: true,
waitProgram: true,
waitMongoProgram: true,
_runningMongoChildProcessIds: true,
startMongoProgramNoConnect: true,
// shell-specific
shellPrintHelper: true,
shellAutocomplete: true,
__autocomplete__: true,
defaultPrompt: true,
___it___: true,
__promptWrapper__: true,
passwordPrompt: true,
isInteractive: true,
// shell-specific
shellPrintHelper: true,
shellAutocomplete: true,
__autocomplete__: true,
defaultPrompt: true,
___it___: true,
__promptWrapper__: true,
passwordPrompt: true,
isInteractive: true,
// built-in BSON types and helpers
Code: true,
MaxKey: true,
MinKey: true,
HexData: true,
DBPointer: true,
DBRef: true,
BinData: true,
NumberLong: true,
NumberDecimal: true,
Timestamp: true,
MD5: true,
Geo: true,
decodeResumeToken: true,
bsonWoCompare: true,
bsonUnorderedFieldsCompare: true,
bsonBinaryEqual: true,
friendlyEqual: true,
timestampCmp: true,
decompressBSONColumn: true,
// built-in BSON types and helpers
Code: true,
MaxKey: true,
MinKey: true,
HexData: true,
DBPointer: true,
DBRef: true,
BinData: true,
NumberLong: true,
NumberDecimal: true,
Timestamp: true,
MD5: true,
Geo: true,
decodeResumeToken: true,
bsonWoCompare: true,
bsonUnorderedFieldsCompare: true,
bsonBinaryEqual: true,
friendlyEqual: true,
timestampCmp: true,
decompressBSONColumn: true,
hex_md5: true,
QueryHelpers: true,
chatty: true,
DriverSession: true,
ToolTest: true,
uncheckedParallelShellPidsString: true,
_shouldRetryWrites: true,
hex_md5: true,
QueryHelpers: true,
chatty: true,
DriverSession: true,
ToolTest: true,
uncheckedParallelShellPidsString: true,
_shouldRetryWrites: true,
// from_cpp:
__prompt__: true,
_replMonitorStats: true,
// from_cpp:
__prompt__: true,
_replMonitorStats: true,
// explainable.js
Explainable: true,
// explainable.js
Explainable: true,
// utils.js
_verboseShell: true,
__quiet: true,
printStackTrace: true,
setVerboseShell: true,
_barFormat: true,
compare: true,
compareOn: true,
shellPrint: true,
_originalPrint: true,
disablePrint: true,
enablePrint: true,
replSetMemberStatePrompt: true,
hasErrorCode: true,
helloStatePrompt: true,
_validateMemberIndex: true,
help: true,
retryOnRetryableError: true,
},
// utils.js
_verboseShell: true,
__quiet: true,
printStackTrace: true,
setVerboseShell: true,
_barFormat: true,
compare: true,
compareOn: true,
shellPrint: true,
_originalPrint: true,
disablePrint: true,
enablePrint: true,
replSetMemberStatePrompt: true,
hasErrorCode: true,
helloStatePrompt: true,
_validateMemberIndex: true,
help: true,
retryOnRetryableError: true,
},
ecmaVersion: 2022,
sourceType: "module",
},
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"no-prototype-builtins": 0,
"no-useless-escape": 0,
"no-irregular-whitespace": 0,
"no-inner-declarations": 0,
plugins: {
"mongodb": mongodb_plugin,
},
"no-unused-vars": [0, {
varsIgnorePattern: "^_",
args: "none",
}],
rules: {
// TODO SERVER-99571 : enable mongodb/* rules.
"mongodb/no-print-fn": 1,
"mongodb/no-tojson-fn": 1,
"no-empty": 0,
"no-redeclare": 0,
"no-constant-condition": 0,
"no-loss-of-precision": 0,
semi: 2,
"no-prototype-builtins": 0,
"no-useless-escape": 0,
"no-irregular-whitespace": 0,
"no-inner-declarations": 0,
"no-restricted-syntax": ["error", {
message: "Invalid load call. Please convert your library to a module and import it instead.",
selector: "CallExpression > Identifier[name=\"load\"]",
}],
},
}];
"no-unused-vars": [
0,
{
varsIgnorePattern: "^_",
args: "none",
}
],
"no-empty": 0,
"no-redeclare": 0,
"no-constant-condition": 0,
"no-loss-of-precision": 0,
semi: 2,
"no-restricted-syntax": [
"error",
{
message:
"Invalid load call. Please convert your library to a module and import it instead.",
selector: "CallExpression > Identifier[name=\"load\"]",
}
],
},
},
{
// It's ok for golden tests to use print() and tojson() directly.
plugins: {
"mongodb": mongodb_plugin,
},
files: [
"jstests/libs/begin_golden_test.js",
"jstests/libs/golden_test.js",
"jstests/libs/override_methods/golden_overrides.js",
"jstests/libs/override_methods/sharded_golden_overrides.js",
"jstests/libs/query/golden_test_utils.js",
"jstests/libs/query_golden_sharding_utils.js",
"jstests/query_golden/**/*.js",
"jstests/query_golden_sharding/**/*.js",
],
rules: {
"mongodb/no-print-fn": 0,
"mongodb/no-tojson-fn": 0,
}
},
{
// Don't run mongodb linter rules on src/
plugins: {
"mongodb": mongodb_plugin,
},
files: [
"src/**/*.js",
],
rules: {
"mongodb/no-print-fn": 0,
"mongodb/no-tojson-fn": 0,
}
}
];

View File

@ -3,11 +3,11 @@
"version": "1.0.0",
"private": true,
"devDependencies": {
"@eslint/js": "^9",
"@eslint/eslintrc": "3.2.0",
"@eslint/js": "^9",
"eslint": "9.19.0",
"globals": "14.0.0",
"eslint-formatter-unix": "^8.40.0",
"globals": "14.0.0",
"prettier": "3.4.2"
},
"pnpm": {

View File

@ -6,28 +6,25 @@ settings:
onlyBuiltDependencies: []
importers:
.:
devDependencies:
'@eslint/eslintrc':
specifier: 3.2.0
version: 3.2.0
'@eslint/js':
specifier: ^9
version: 9.19.0
eslint:
specifier: 9.19.0
version: 9.19.0
eslint-formatter-unix:
specifier: ^8.40.0
version: 8.40.0
globals:
specifier: 14.0.0
version: 14.0.0
prettier:
specifier: 3.4.2
version: 3.4.2
devDependencies:
'@eslint/eslintrc':
specifier: 3.2.0
version: 3.2.0
'@eslint/js':
specifier: ^9
version: 9.19.0
eslint:
specifier: 9.19.0
version: 9.19.0
eslint-formatter-unix:
specifier: ^8.40.0
version: 8.40.0
globals:
specifier: 14.0.0
version: 14.0.0
prettier:
specifier: 3.4.2
version: 3.4.2
packages: