#!/usr/bin/env python3 """Advisory reminder for subsystem fast tests + opt-in live performance tests. When staged source files touch a subsystem listed in PATH_RULES, print a two-tier reminder: (1) the narrow fast mocked tests that catch logic/contract regressions in seconds, and (2) the opt-in live performance tests under ``tests/performance//`` — plus a nudge to add one if the subsystem doesn't have a live-tests dir yet. Always exits 0 (advisory). Mirrors recommend-tests.py style. """ import sys from pathlib import Path # Allow importing sibling module sys.path.insert(0, str(Path(__file__).resolve().parent)) from _commit_analysis import analyze_commit # Keep this table at the top of the file — update it alongside any # reshuffling of tests/performance// directories or when a # new subsystem grows a fast-test suite worth recommending. # # Rules are evaluated most-specific-first: a staged file is attributed # to the FIRST matching rule only, so overlapping prefixes # (e.g. relevance_filter.py is inside web_search_engines/) don't # fire two reminders. PATH_RULES = [ { "name": "relevance_filter", "prefixes": ( "src/local_deep_research/web_search_engines/relevance_filter.py", ), "fast_tests": [ "tests/web_search_engines/test_relevance_filter.py", ], "perf_dir": "tests/performance/relevance_filter/", "perf_exists": True, }, { "name": "search_engine_adapters", "prefixes": ("src/local_deep_research/web_search_engines/engines/",), "fast_tests": [ "tests/web_search_engines/test_search_engine_base.py", "tests/web_search_engines/engines/test_full_search.py", ], "perf_dir": "tests/performance/search_engines/", "perf_exists": True, }, { "name": "web_search_engines", "prefixes": ("src/local_deep_research/web_search_engines/",), "fast_tests": [ "tests/web_search_engines/test_search_engine_base.py", "tests/web_search_engines/test_search_engine_factory.py", ], "perf_dir": None, "perf_exists": False, }, { "name": "advanced_search_system", "prefixes": ("src/local_deep_research/advanced_search_system/",), "fast_tests": [ "tests/advanced_search_system/constraint_checking/test_threshold_checker.py", "tests/advanced_search_system/constraint_checking/test_dual_confidence_checker.py", "tests/advanced_search_system/constraint_checking/test_base_constraint_checker.py", ], "perf_dir": "tests/performance/strategies/", "perf_exists": True, }, { "name": "content_fetcher", "prefixes": ( "src/local_deep_research/content_fetcher/", "src/local_deep_research/research_library/downloaders/", ), "fast_tests": [ "tests/content_fetcher/test_html_content_extraction.py", "tests/research_library/downloaders/test_html_downloader.py", "tests/research_library/downloaders/test_extraction_pipeline.py", "tests/research_library/downloaders/test_metadata_extractor.py", ], "perf_dir": "tests/performance/content_fetcher/", "perf_exists": True, }, ] def _print_rule(rule, matched): print() print(f" \033[33mPerformance Test Reminder — {rule['name']}\033[0m") print(" " + "-" * 40) print(f" You touched {len(matched)} file(s) under {rule['name']}:") for p in matched: print(f" - {p}") print() print(" Fast tests (mocked, ~5-30s) to run now:") print(f" pdm run pytest {' '.join(rule['fast_tests'])}") print() if rule["perf_exists"]: print(" Heavier real-service tests (opt-in, live):") print( f" LDR_TESTING_WITH_MOCKS=false pdm run pytest " f"{rule['perf_dir']} -m integration" ) print( " If you added behavior only live tests catch, consider " f"adding a test under {rule['perf_dir']}." ) elif rule["perf_dir"]: print( f" No live tests exist yet at {rule['perf_dir']}. If your " "change needs live-service coverage, consider adding one." ) else: print( " No live-tests dir for this subsystem yet — consider " "adding one if live coverage matters." ) print() def main(): analysis = analyze_commit() if not analysis.source_files: return 0 staged = [f.path for f in analysis.source_files] # First-match-wins assignment so overlapping prefixes # (relevance_filter.py is inside web_search_engines/) don't # double-fire. PATH_RULES is ordered most-specific-first. per_rule: dict[str, list[str]] = {} for path in staged: for rule in PATH_RULES: if path.startswith(rule["prefixes"]): per_rule.setdefault(rule["name"], []).append(path) break for rule in PATH_RULES: matched = per_rule.get(rule["name"], []) if matched: _print_rule(rule, matched) return 0 if __name__ == "__main__": sys.exit(main())