SERVER-122557: Ensure streams js tests are added to a suite (#50997)
GitOrigin-RevId: bd31b4fa0500dae49706cfa6c6d6400475dd15e5
This commit is contained in:
parent
a525168b24
commit
b667e47712
@ -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"])
|
||||
|
||||
|
||||
@ -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"],
|
||||
|
||||
@ -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
|
||||
@ -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:
|
||||
|
||||
141
buildscripts/streams_suite_coverage_linter.py
Normal file
141
buildscripts/streams_suite_coverage_linter.py
Normal 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())
|
||||
@ -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
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user