diff --git a/localstack-core/localstack/testing/testselection/matching.py b/localstack-core/localstack/testing/testselection/matching.py index 2d9025b240bef..4bf5e9bfaca2d 100644 --- a/localstack-core/localstack/testing/testselection/matching.py +++ b/localstack-core/localstack/testing/testselection/matching.py @@ -93,8 +93,12 @@ def service_tests(self, services: list[str]): def passthrough(self): return lambda t: [t] if self.matching_func(t) else [] - def directory(self): - return lambda t: [get_directory(t)] if self.matching_func(t) else [] + def directory(self, paths: list[str] = None): + """Enables executing tests on a full directory if the file is matched. + By default, it will return the directory of the modified file. + If the argument `paths` is provided, it will instead return the provided list. + """ + return lambda t: (paths or [get_directory(t)]) if self.matching_func(t) else [] class Matchers: diff --git a/tests/unit/testing/testselection/test_matching.py b/tests/unit/testing/testselection/test_matching.py index 8cf7c9fdde7c9..885d4d83ceff4 100644 --- a/tests/unit/testing/testselection/test_matching.py +++ b/tests/unit/testing/testselection/test_matching.py @@ -6,10 +6,13 @@ from localstack.testing.testselection.matching import ( MATCHING_RULES, + SENTINEL_ALL_TESTS, + Matchers, check_rule_has_matches, generic_service_test_matching_rule, resolve_dependencies, ) +from localstack.testing.testselection.testselection import get_affected_tests_from_changes def test_service_dependency_resolving_no_deps(): @@ -104,3 +107,34 @@ def test_rules_are_matching_at_least_one_file(): files = [os.path.relpath(f, root_dir) for f in files] for rule_id, rule in enumerate(MATCHING_RULES): assert check_rule_has_matches(rule, files), f"no match for rule {rule_id}" + + +def test_directory_rules_with_paths(): + feature_path = "localstack/my_feature" + test_path = "test/my_feature" + matcher = Matchers.glob(f"{feature_path}/**").directory(paths=[test_path]) + selected_tests = get_affected_tests_from_changes([f"{feature_path}/__init__.py"], [matcher]) + + assert selected_tests == [test_path] + + +def test_directory_rules_no_paths(): + conftest_path = "**/conftest.py" + matcher = Matchers.glob(conftest_path).directory() + + selected_tests = get_affected_tests_from_changes( + ["tests/aws/service/sns/conftest.py"], [matcher] + ) + + assert selected_tests == ["tests/aws/service/sns/"] + + +def test_directory_rules_no_match(): + feature_path = "localstack/my_feature" + test_path = "test/my_feature" + matcher = Matchers.glob(f"{feature_path}/**").directory(paths=[test_path]) + selected_tests = get_affected_tests_from_changes( + ["localstack/not_my_feature/__init__.py"], [matcher] + ) + + assert selected_tests == [SENTINEL_ALL_TESTS]