This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new bc788418d95 Fix excluded provider tests crashing pytest (#63918)
bc788418d95 is described below

commit bc788418d95eefe7e9f03c86731844160bcfb529
Author: Dev-iL <[email protected]>
AuthorDate: Thu Mar 19 12:48:30 2026 +0200

    Fix excluded provider tests crashing pytest (#63918)
    
    When running provider tests (e.g., Providers[google]) on a Python version
    where the provider is excluded, generate_args_for_pytest removes the test
    directories but the skip check in _run_test only triggers when its own
    --ignore filter removes something. Since the directories are already gone,
    pytest runs with zero test directories and crashes on unrecognized custom
    arguments like --run-db-tests-only.
    
    Add are_all_test_paths_excluded() that explicitly checks whether all test
    paths for the given test type are in the excluded/suspended provider set,
    using the same provider.yaml data. Call it early in _run_test to skip
    before any Docker operations.
---
 .../airflow_breeze/commands/testing_commands.py    | 10 +++++
 dev/breeze/src/airflow_breeze/utils/run_tests.py   | 38 ++++++++++++++++++
 dev/breeze/tests/test_run_test_args.py             | 45 ++++++++++++++++++++++
 3 files changed, 93 insertions(+)

diff --git a/dev/breeze/src/airflow_breeze/commands/testing_commands.py 
b/dev/breeze/src/airflow_breeze/commands/testing_commands.py
index a6aa6ef021c..3ee2e605614 100644
--- a/dev/breeze/src/airflow_breeze/commands/testing_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/testing_commands.py
@@ -114,6 +114,7 @@ from airflow_breeze.utils.parallel import (
 from airflow_breeze.utils.path_utils import AIRFLOW_CTL_ROOT_PATH, FILES_PATH, 
cleanup_python_generated_files
 from airflow_breeze.utils.run_tests import (
     TASK_SDK_INTEGRATION_TESTS_ROOT_PATH,
+    are_all_test_paths_excluded,
     file_name_from_test_type,
     generate_args_for_pytest,
     run_docker_compose_tests,
@@ -206,6 +207,15 @@ def _run_test(
             "[error]Only 'Providers' test type can specify actual tests with 
\\[\\][/]"
         )
         sys.exit(1)
+    if are_all_test_paths_excluded(
+        test_group=shell_params.test_group,
+        test_type=shell_params.test_type,
+        python_version=python_version,
+        skip_db_tests=shell_params.skip_db_tests,
+        parallel_test_types_list=shell_params.parallel_test_types_list,
+        integration=shell_params.integration,
+    ):
+        return 0, f"Skipped test, no tests needed: {shell_params.test_type}"
     compose_project_name, project_name = _get_project_names(shell_params)
     env = shell_params.env_variables_for_docker_commands
     down_cmd = [
diff --git a/dev/breeze/src/airflow_breeze/utils/run_tests.py 
b/dev/breeze/src/airflow_breeze/utils/run_tests.py
index b14818f028c..5cd4e6692d8 100644
--- a/dev/breeze/src/airflow_breeze/utils/run_tests.py
+++ b/dev/breeze/src/airflow_breeze/utils/run_tests.py
@@ -227,6 +227,44 @@ def get_excluded_test_provider_folders(python_version: 
str) -> list[str]:
     return get_test_folders(excluded_folders)
 
 
+def are_all_test_paths_excluded(
+    *,
+    test_group: GroupOfTests,
+    test_type: str,
+    python_version: str,
+    skip_db_tests: bool = False,
+    parallel_test_types_list: list[str] | None = None,
+    integration: tuple | None = None,
+) -> bool:
+    """Check if all test paths for the given test type are excluded or 
suspended.
+
+    Uses the same provider.yaml exclusion data as generate_args_for_pytest to 
determine
+    whether every test directory that would be generated for this test type is 
in the
+    excluded or suspended provider set.
+
+    Returns False when test_type is "None" (user provides explicit paths via 
extra_pytest_args)
+    or when any test path remains after exclusions.
+    """
+    if skip_db_tests and parallel_test_types_list:
+        initial_paths = convert_parallel_types_to_folders(
+            test_group=test_group,
+            parallel_test_types_list=parallel_test_types_list,
+        )
+    else:
+        initial_paths = convert_test_type_to_pytest_args(
+            test_group=test_group,
+            test_type=test_type,
+            integration=integration,
+        )
+    # Filter to only actual test directory paths (not pytest flags like -m, 
--include-quarantined)
+    test_dir_paths = [p for p in initial_paths if not p.startswith("-")]
+    if not test_dir_paths:
+        return False
+    excluded = set(get_excluded_test_provider_folders(python_version))
+    suspended = set(get_suspended_test_provider_folders())
+    return all(p in excluded | suspended for p in test_dir_paths)
+
+
 TEST_TYPE_CORE_MAP_TO_PYTEST_ARGS: dict[str, list[str]] = {
     "Always": ["airflow-core/tests/unit/always"],
     "API": ["airflow-core/tests/unit/api", 
"airflow-core/tests/unit/api_fastapi"],
diff --git a/dev/breeze/tests/test_run_test_args.py 
b/dev/breeze/tests/test_run_test_args.py
index 446d49fe0dd..454787eb74b 100644
--- a/dev/breeze/tests/test_run_test_args.py
+++ b/dev/breeze/tests/test_run_test_args.py
@@ -107,3 +107,48 @@ def 
test_test_is_skipped_if_all_are_ignored(mock_run_command):
     )
 
     mock_run_command.assert_called_once()  # called only to compose down
+
+
+def test_test_is_skipped_when_all_providers_excluded_for_python_version(
+    mock_run_command, mock_get_excluded_provider_folders
+):
+    """When all providers in the test type are excluded for the Python 
version, skip without Docker calls."""
+    mock_get_excluded_provider_folders.return_value = ["http"]
+    return_code, message = _run_test(
+        shell_params=ShellParams(test_group=GroupOfTests.PROVIDERS, 
test_type="Providers[http]"),
+        extra_pytest_args=(),
+        python_version="3.14",
+        output=None,
+        test_timeout=60,
+        skip_docker_compose_down=True,
+    )
+    assert return_code == 0
+    assert "Skipped" in message
+    mock_run_command.assert_not_called()
+
+
+def test_test_is_not_skipped_when_some_providers_remain(mock_run_command, 
mock_get_excluded_provider_folders):
+    """When only some providers are excluded, the test should still run."""
+    mock_get_excluded_provider_folders.return_value = ["http"]
+    _run_test(
+        shell_params=ShellParams(test_group=GroupOfTests.PROVIDERS, 
test_type="Providers[http,standard]"),
+        extra_pytest_args=(),
+        python_version="3.14",
+        output=None,
+        test_timeout=60,
+        skip_docker_compose_down=True,
+    )
+    assert mock_run_command.call_count >= 2  # compose down + compose run
+
+
+def test_none_test_type_with_extra_args_does_not_skip(mock_run_command):
+    """test_type=None with user-provided test paths via extra_pytest_args must 
not skip."""
+    _run_test(
+        shell_params=ShellParams(test_group=GroupOfTests.CORE, 
test_type="None"),
+        
extra_pytest_args=("airflow-core/tests/unit/serialization/test_helpers.py",),
+        python_version="3.14",
+        output=None,
+        test_timeout=60,
+        skip_docker_compose_down=True,
+    )
+    assert mock_run_command.call_count >= 2  # compose down + compose run

Reply via email to