Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions tests/integration/defs/thirdparty/test_cmake_third_party.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
"""Find bad third-party usage in cmake.

This script searches for cmake function invocations that might indicate
the addition of new third-party dependencies outside of the intended
process (3rdparty/README.md).
"""

import argparse
import collections
import logging
import os
import pathlib
import sys
from typing import Generator

logger = logging.getLogger(__name__)

IGNORE_PATTERNS = [
".*", # Hidden files and directories, like .git
# This is where we actually want third-party stuff to go
"3rdparty/CMakeLists.txt",
# Historical use of ExternalProject_Add that is not yet migrated to 3rdparty
"cpp/tensorrt_llm/deep_ep/CMakeLists.txt",
# Historical build that is not included in the wheel build and thus exempt
# from the third-party process.
"triton_backend/inflight_batcher_llm/*",
"build", # Default build directory
"cpp/build", # Default extension module build directory
]


class DirectoryFilter:
"""Callable filter for directories.

This filter excludes any paths matching IGNORE_PATTERNS.
"""

def __init__(self, parent: pathlib.Path):
self.parent = parent

def __call__(self, name: str) -> bool:
path = self.parent / name
if any(path.match(pat) for pat in IGNORE_PATTERNS):
return False
return True


class FileFilter:
"""Callable filter for file entries.

In order of precedence:

1. excludes any paths matching IGNORE_PATTERNS
2. includes only CMakeLists.txt and *.cmake files
"""

def __init__(self, parent: pathlib.Path):
self.parent = parent

def __call__(self, name: str) -> bool:
path = self.parent / name
if any(path.match(pat) for pat in IGNORE_PATTERNS):
return False

if name == "CMakeLists.txt":
return True
elif name.endswith(".cmake"):
return True

return False


def yield_sources(src_tree: pathlib.Path):
"""Perform a filesystem walk and yield any paths that should be scanned."""
for parent, dirs, files in os.walk(src_tree):
parent = pathlib.Path(parent)
relpath_parent = parent.relative_to(src_tree)

# Filter out ignored directories
dirs[:] = sorted(filter(DirectoryFilter(relpath_parent), dirs))

for file in sorted(filter(FileFilter(relpath_parent), files)):
yield parent / file


ThirdpartyViolation = collections.namedtuple(
"ThirdpartyViolation", ["srcfile", "lineno", "note", "line"]
)


def yield_potential_thirdparty(
fullpath: pathlib.Path, relpath: pathlib.Path
) -> Generator[ThirdpartyViolation, None, None]:
"""Look for bad patterns with third-party sources.

Look for patterns that might indicate the addition of new third-party
sources.
"""
with fullpath.open("r", encoding="utf-8") as infile:
for lineno, line in enumerate(infile):
lineno += 1 # Make line numbers 1-based

if "FetchContent_Declare" in line:
note = "Invalid use of FetchContent_Declare outside of 3rdparty/CMakeLists.txt"
yield ThirdpartyViolation(relpath, lineno, note, line.strip())

if "ExternalProject_Add" in line:
note = "Invalid use of ExternalProject_Add outside of 3rdparty/CMakeLists.txt"
yield ThirdpartyViolation(relpath, lineno, note, line.strip())


def check_sources(src_tree: pathlib.Path) -> int:
"""Common entry-point between main() and pytest.

Prints any violations to stderr and returns non-zero if any violations are
found.
"""
violations = []
for filepath in yield_sources(src_tree):
for violation in yield_potential_thirdparty(filepath, filepath.relative_to(src_tree)):
violations.append(violation)

if not violations:
return 0

for violation in sorted(violations):
sys.stderr.write(
f"{violation.srcfile}:{violation.lineno}: {violation.note}\n"
+ f" {violation.line}\n"
)

logger.error(
"Found %d potential third-party violations. "
"If you are trying to add a new third-party dependency, "
"please follow the instructions in 3rdparty/cpp-thirdparty.md",
len(violations),
)
return 1


def test_cmake_listfiles():
"""Test that no third-party violations are found in the source tree."""
source_tree = pathlib.Path(__file__).parents[1]
result = check_sources(source_tree)
assert result == 0


def main():
parser = argparse.ArgumentParser(description="__doc__")
parser.add_argument(
"--src-tree",
default=pathlib.Path.cwd(),
type=pathlib.Path,
help="Path to the source tree, defaults to current directory",
)
args = parser.parse_args()
result = check_sources(args.src_tree)
sys.exit(result)


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
main()
105 changes: 105 additions & 0 deletions tests/integration/defs/thirdparty/test_git_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"""This script audits the .gitmodules file.

... to make sure that new git submodules are not added without following the
proper process (cpp/3rdparty/cpp-thirdparty.md)
"""

import argparse
import collections
import configparser
import logging
import pathlib
import sys

logger = logging.getLogger(__name__)

ALLOWLIST_SUBMODULES = [
# NOTE: please do not add new sobmodules here without following the process
# in 3rdparty/cpp-thirdparty.md. Prefer to use FetchContent or other methods
# to avoid adding new git submodules unless absolutely necessary.
]

ThirdpartyViolation = collections.namedtuple("ThirdpartyViolation", ["section", "path", "note"])


def find_violations(config: configparser.ConfigParser) -> list[str]:
violations = []
for section in config.sections():
if not section.startswith("submodule "):
raise ValueError(f"Unexpected section in .gitmodules: {section}")

path = config[section].get("path", "")
if not path:
raise ValueError(f"Missing path for submodule {section}")

if path not in ALLOWLIST_SUBMODULES:
violations.append(
ThirdpartyViolation(
section=section,
path=path,
note="Submodule not in allowlist (see test_git_modules.py)",
)
)

if not path.startswith("3rdparty/"):
violations.append(
ThirdpartyViolation(
section=section,
path=path,
note="Submodule path must be under 3rdparty/",
)
)
return violations


def check_modules_file(git_modules_path: pathlib.Path) -> int:
"""Common entry-point between main() and pytest.

Prints any violations to stderr and returns non-zero if any violations are
found.
"""
config = configparser.ConfigParser()
config.read(git_modules_path)

violations = find_violations(config)

if violations:
for violation in violations:
sys.stderr.write(f"{violation.section} (path={violation.path}): {violation.note}\n")

logger.error(
"Found %d potential third-party violations. "
"If you are trying to add a new third-party dependency, "
"please follow the instructions in cpp/3rdparty/cpp-thirdparty.md",
len(violations),
)
return 1
return 0


def test_gitmodules():
"""Test that no git submodules are added to .gitmodules.

... without following the defined process.
"""
git_modules_path = pathlib.Path(__file__).parents[1] / ".gitmodules"
result = check_modules_file(git_modules_path)
assert result == 0


def main():
parser = argparse.ArgumentParser(description="__doc__")
parser.add_argument(
"--git-modules-path",
default=pathlib.Path(".gitmodules"),
type=pathlib.Path,
help="Path to the .gitmodules file, defaults to .gitmodules in current directory",
)
args = parser.parse_args()
result = check_modules_file(args.git_modules_path)
sys.exit(result)


if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
main()
3 changes: 3 additions & 0 deletions tests/integration/test_lists/test-db/l0_a10.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ l0_a10:
- llmapi/test_llm_api_connector.py::test_connector_disagg_prefill[False]
- llmapi/test_llm_api_connector.py::test_connector_disagg_prefill[True]
- llmapi/test_llm_api_connector.py::test_connector_multi_request
# third-party policy checks CPU-only
- thirdparty/test_cmake_third_party.py::test_cmake_listfiles
- thirdparty/test_git_modules.py::test_gitmodules
- condition:
ranges:
system_gpu_count:
Expand Down