SERVER-122557: Ensure streams js tests are added to a suite (#50997)

GitOrigin-RevId: bd31b4fa0500dae49706cfa6c6d6400475dd15e5
This commit is contained in:
Daniel Gil 2026-04-02 10:32:27 -04:00 committed by MongoDB Bot
parent a525168b24
commit b667e47712
8 changed files with 200 additions and 0 deletions

View File

@ -602,6 +602,12 @@ def run_rules_lint(bazel_bin: str, args: list[str]):
lr.run_bazel("//buildscripts:yamllinters")
print("No errors found in evergreen yaml")
if lint_all or any(
"jstests/streams" in file or "resmokeconfig/suites/streams" in file
for file in files_to_lint
):
lr.run_bazel("//buildscripts:streams_suite_coverage_linter")
if lint_all or any(file.endswith(".md") for file in files_to_lint):
lr.run_bazel("//buildscripts:markdown_link_linter", ["--root=src/mongo", "--verbose"])

View File

@ -522,6 +522,19 @@ py_binary(
deps = [], # 'requests' optional (external link checks skipped if absent)
)
py_binary(
name = "streams_suite_coverage_linter",
srcs = ["streams_suite_coverage_linter.py"],
main = "streams_suite_coverage_linter.py",
visibility = ["//visibility:public"],
deps = [
dependency(
"pyyaml",
group = "core",
),
],
)
py_binary(
name = "yamllinters",
srcs = ["yamllinters.py"],

View File

@ -0,0 +1,21 @@
test_kind: js_test
selector:
roots:
- src/mongo/db/modules/*/jstests/streams/aspio/iceberg/iceberg_duplicate_rows.js
- src/mongo/db/modules/*/jstests/streams/aspio/iceberg/iceberg_snapshot_lineage.js
- src/mongo/db/modules/*/jstests/streams/aspio/iceberg/iceberg_stats.js
exclude_files:
# TODO(SERVER-117494): Re-enable once flakiness is resolved.
- src/mongo/db/modules/*/jstests/streams/aspio/iceberg/gwproxy/iceberg_gwproxy.js
executor:
fixture:
class: ReplicaSetFixture
mongod_options:
bind_ip_all: ""
set_parameters:
enableTestCommands: 1
featureFlagStreams: true
diagnosticDataCollectionEnabled: false
num_nodes: 1

View File

@ -8,6 +8,8 @@ selector:
- src/mongo/db/modules/enterprise/jstests/streams/aspio/iceberg/iceberg_benchmark_tpcc_official.js
# TODO(SERVER-122755): Move this elsewhere
- src/mongo/db/modules/enterprise/jstests/streams/aspio/iceberg/s3_emit_benchmark_tpcc.js
- src/mongo/db/modules/enterprise/jstests/streams/aspio/iceberg/iceberg_speed_test.js
- src/mongo/db/modules/enterprise/jstests/streams/aspio/pubsub/pubsub_benchmark_tpcc.js
executor:
fixture:

View File

@ -0,0 +1,141 @@
#!/usr/bin/env python3
"""Verify every jstest under streams directories is referenced by at least one resmoke suite.
Exits 0 when all test files are covered, 1 otherwise.
Usage:
python3 buildscripts/resmoke_suite_coverage_linter.py
"""
import fnmatch
import glob
import os
import pathlib
import sys
import yaml
REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
ENTERPRISE_MODULE = REPO_ROOT / "src" / "mongo" / "db" / "modules" / "enterprise"
JSTESTS_DIRS = [
ENTERPRISE_MODULE / "jstests" / "streams",
ENTERPRISE_MODULE / "jstests" / "streams_kafka",
]
SUITE_DIR = REPO_ROOT / "buildscripts" / "resmokeconfig" / "suites"
SUITE_GLOB = "streams*.yml"
# Filename patterns for non-test helper files that are loaded by tests
# rather than executed directly by resmoke.
NON_TEST_PATTERNS: list[str] = [
"*_utils.js",
"benchmark_utils.js",
"*_harness.js",
"*_common.js",
]
# Directories whose contents are never standalone tests (libraries,
# fixture data, helper functions, etc.).
NON_TEST_DIRS: set[str] = {
"lib",
"data",
"function",
"mongostream_container_manager",
}
def _is_non_test_file(filename: str) -> bool:
return any(fnmatch.fnmatch(filename, pat) for pat in NON_TEST_PATTERNS)
def _is_in_non_test_dir(path: pathlib.Path, jstests_dir: pathlib.Path) -> bool:
rel = path.relative_to(jstests_dir)
return any(part in NON_TEST_DIRS for part in rel.parts)
def find_all_js_test_files() -> set[str]:
"""Find all .js files under streams jstests directories, excluding known non-test files.
Returns paths relative to REPO_ROOT.
"""
files: set[str] = set()
for jstests_dir in JSTESTS_DIRS:
if not jstests_dir.is_dir():
continue
for root, _dirs, filenames in os.walk(jstests_dir):
root_path = pathlib.Path(root)
if _is_in_non_test_dir(root_path, jstests_dir):
continue
for f in filenames:
if not f.endswith(".js"):
continue
if _is_non_test_file(f):
continue
full = root_path / f
files.add(str(full.relative_to(REPO_ROOT)))
return files
def _normalize_suite_path(path: str) -> str:
"""Replace the module wildcard with the concrete enterprise path."""
return path.replace("modules/*/", "modules/enterprise/")
def get_suite_covered_files() -> set[str]:
"""Parse all streams suite YAMLs and return the set of covered file paths.
Returns paths relative to REPO_ROOT.
"""
covered: set[str] = set()
suite_files = sorted(SUITE_DIR.glob(SUITE_GLOB))
for suite_file in suite_files:
with open(suite_file, encoding="utf-8") as fh:
config = yaml.safe_load(fh)
if not config or "selector" not in config:
continue
selector = config["selector"]
for root_pattern in selector.get("roots", []):
full_pattern = str(REPO_ROOT / _normalize_suite_path(root_pattern))
for match in glob.glob(full_pattern):
covered.add(os.path.relpath(match, REPO_ROOT))
for excl_pattern in selector.get("exclude_files", []):
full_pattern = str(REPO_ROOT / _normalize_suite_path(excl_pattern))
for match in glob.glob(full_pattern):
covered.add(os.path.relpath(match, REPO_ROOT))
return covered
def main() -> int:
all_tests = find_all_js_test_files()
covered = get_suite_covered_files()
uncovered = sorted(all_tests - covered)
if not uncovered:
print("All streams jstests are covered by resmoke suites!")
return 0
print(f"Found {len(uncovered)} streams jstest(s) not referenced by any resmoke suite:\n")
for f in uncovered:
print(f" {f}")
print(
"\nPlease add each test to the appropriate streams*.yml suite config in\n"
"buildscripts/resmokeconfig/suites/\n"
"\n"
"If a file is not a standalone test (e.g. a utility loaded by other tests),\n"
"add its filename pattern to NON_TEST_PATTERNS or NON_TEST_DIRS in\n"
"buildscripts/streams_suite_coverage_linter.py"
)
return 1
if __name__ == "__main__":
sys.exit(main())

View File

@ -14,6 +14,7 @@ selector:
- streams_aspio_iceberg_1
- streams_aspio_iceberg_2
- streams_aspio_iceberg_3
- streams_aspio_iceberg_4
- streams_aspio_iceberg_large
- streams_aspio_iceberg_5
- streams_aspio_utilities

View File

@ -185,6 +185,7 @@ rules:
"streams_aspio_iceberg_1",
"streams_aspio_iceberg_2",
"streams_aspio_iceberg_3",
"streams_aspio_iceberg_4",
"streams_aspio_iceberg_large",
"streams_aspio_iceberg_5",
"streams_aspio_utilities",

View File

@ -491,6 +491,21 @@ tasks:
vars:
resmoke_jobs_max: 4
- <<: *task_template_streams
name: streams_aspio_iceberg_4
tags:
[
"assigned_to_jira_team_streams",
"experimental",
"streams_release_test",
"requires_extra_system_deps",
]
commands:
- func: "do setup for streams"
- func: "run streams tests"
vars:
resmoke_jobs_max: 4
- <<: *task_template_streams
name: streams_aspio_iceberg_large
tags: