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

shahar1 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 6d8a58bff74 Exempt Google Cloud link modules from provider test-file 
check (#74924)
6d8a58bff74 is described below

commit 6d8a58bff74671eb47c9e32ba386e258e01dc351
Author: Shahar Epstein <[email protected]>
AuthorDate: Tue Oct 20 22:57:23 2026 +0300

    Exempt Google Cloud link modules from provider test-file check (#74924)
    
    Link modules only define link classes, so their tests would only assert
    constants (name, key, format_str). Move them to a dedicated EXEMPTED_TESTS
    list in test_providers_modules_should_have_tests and delete the
    constant-only test files. Stale and added-test checks apply to the new list
    as they do to OVERLOOKED_TESTS.
---
 .../tests/unit/always/test_project_structure.py    | 55 +++++++++------
 .../tests/unit/google/cloud/links/test_alloy_db.py | 62 -----------------
 .../unit/google/cloud/links/test_managed_kafka.py  | 79 ----------------------
 3 files changed, 36 insertions(+), 160 deletions(-)

diff --git a/airflow-core/tests/unit/always/test_project_structure.py 
b/airflow-core/tests/unit/always/test_project_structure.py
index 514e3b16cde..a9d12c05600 100644
--- a/airflow-core/tests/unit/always/test_project_structure.py
+++ b/airflow-core/tests/unit/always/test_project_structure.py
@@ -58,8 +58,8 @@ class TestProjectStructure:
         """
         Assert every module in /providers/ has a corresponding test_ file in 
providers/providers.
         """
-        # The test below had a but for quite a while and we missed a lot of 
modules to have tess
-        # We should make sure that one goes to 0
+        # A long-standing bug in the test below allowed modules without tests 
to go undetected.
+        # This list tracks those modules and should shrink to zero as tests 
are added.
         OVERLOOKED_TESTS = [
             
"providers/amazon/tests/unit/amazon/aws/auth_manager/datamodels/test_login.py",
             
"providers/amazon/tests/unit/amazon/aws/executors/batch/test_batch_executor_config.py",
@@ -90,24 +90,8 @@ class TestProjectStructure:
             "providers/fab/tests/unit/fab/www/test_security_appless.py",
             "providers/fab/tests/unit/fab/www/test_security_manager.py",
             "providers/fab/tests/unit/fab/www/test_session.py",
-            
"providers/google/tests/unit/google/cloud/links/test_bigquery_dts.py",
-            "providers/google/tests/unit/google/cloud/links/test_bigtable.py",
-            
"providers/google/tests/unit/google/cloud/links/test_cloud_build.py",
-            
"providers/google/tests/unit/google/cloud/links/test_cloud_functions.py",
-            
"providers/google/tests/unit/google/cloud/links/test_cloud_memorystore.py",
-            "providers/google/tests/unit/google/cloud/links/test_cloud_sql.py",
-            "providers/google/tests/unit/google/cloud/links/test_compute.py",
-            
"providers/google/tests/unit/google/cloud/links/test_data_loss_prevention.py",
-            "providers/google/tests/unit/google/cloud/links/test_dataflow.py",
-            "providers/google/tests/unit/google/cloud/links/test_dataform.py",
-            
"providers/google/tests/unit/google/cloud/links/test_datafusion.py",
-            "providers/google/tests/unit/google/cloud/links/test_dataprep.py",
             "providers/google/tests/unit/google/cloud/links/test_dataproc.py",
-            "providers/google/tests/unit/google/cloud/links/test_datastore.py",
             
"providers/google/tests/unit/google/cloud/links/test_kubernetes_engine.py",
-            "providers/google/tests/unit/google/cloud/links/test_pubsub.py",
-            "providers/google/tests/unit/google/cloud/links/test_spanner.py",
-            "providers/google/tests/unit/google/cloud/links/test_workflows.py",
             "providers/google/tests/unit/google/cloud/links/test_translate.py",
             
"providers/google/tests/unit/google/cloud/operators/vertex_ai/test_auto_ml.py",
             
"providers/google/tests/unit/google/cloud/operators/vertex_ai/test_batch_prediction_job.py",
@@ -125,6 +109,28 @@ class TestProjectStructure:
             
"providers/microsoft/azure/tests/unit/microsoft/azure/operators/test_adls.py",
             
"providers/snowflake/tests/unit/snowflake/triggers/test_snowflake_trigger.py",
         ]
+        # Deliberately untested: link modules whose tests would only assert 
constants.
+        # Remove an entry once its module gains logic worth testing.
+        EXEMPTED_TESTS = [
+            "providers/google/tests/unit/google/cloud/links/test_alloy_db.py",
+            
"providers/google/tests/unit/google/cloud/links/test_bigquery_dts.py",
+            "providers/google/tests/unit/google/cloud/links/test_bigtable.py",
+            
"providers/google/tests/unit/google/cloud/links/test_cloud_build.py",
+            
"providers/google/tests/unit/google/cloud/links/test_cloud_functions.py",
+            
"providers/google/tests/unit/google/cloud/links/test_cloud_memorystore.py",
+            "providers/google/tests/unit/google/cloud/links/test_cloud_sql.py",
+            "providers/google/tests/unit/google/cloud/links/test_compute.py",
+            
"providers/google/tests/unit/google/cloud/links/test_data_loss_prevention.py",
+            "providers/google/tests/unit/google/cloud/links/test_dataflow.py",
+            "providers/google/tests/unit/google/cloud/links/test_dataform.py",
+            
"providers/google/tests/unit/google/cloud/links/test_datafusion.py",
+            "providers/google/tests/unit/google/cloud/links/test_dataprep.py",
+            "providers/google/tests/unit/google/cloud/links/test_datastore.py",
+            
"providers/google/tests/unit/google/cloud/links/test_managed_kafka.py",
+            "providers/google/tests/unit/google/cloud/links/test_pubsub.py",
+            "providers/google/tests/unit/google/cloud/links/test_spanner.py",
+            "providers/google/tests/unit/google/cloud/links/test_workflows.py",
+        ]
         modules_files: list[pathlib.Path] = list(
             
AIRFLOW_PROVIDERS_ROOT_PATH.glob("**/src/airflow/providers/**/*.py")
         )
@@ -170,12 +176,18 @@ class TestProjectStructure:
             ]
         )
         overlooked_test_files = {pathlib.Path(test_file) for test_file in 
OVERLOOKED_TESTS}
+        exempted_test_files = {pathlib.Path(test_file) for test_file in 
EXEMPTED_TESTS}
         stale_overlooked_tests = overlooked_test_files - expected_test_files
         assert not stale_overlooked_tests, (
             "Detected stale provider test exemptions without corresponding 
provider modules - "
             f"please remove them from OVERLOOKED_TESTS: 
{sorted(stale_overlooked_tests)}"
         )
-        expected_test_files -= overlooked_test_files
+        stale_exempted_tests = exempted_test_files - expected_test_files
+        assert not stale_exempted_tests, (
+            "Detected stale provider test exemptions without corresponding 
provider modules - "
+            f"please remove them from EXEMPTED_TESTS: 
{sorted(stale_exempted_tests)}"
+        )
+        expected_test_files -= overlooked_test_files | exempted_test_files
 
         missing_tests_files = [
             file.as_posix()
@@ -189,6 +201,11 @@ class TestProjectStructure:
             "Detect added tests in providers module - please remove the tests "
             "from OVERLOOKED_TESTS list above"
         )
+        added_exempted_test_files = 
current_test_files.intersection(exempted_test_files)
+        assert set() == added_exempted_test_files, (
+            "Detect added tests in providers module - please remove the tests "
+            f"from EXEMPTED_TESTS list above: 
{sorted(added_exempted_test_files)}"
+        )
 
 
 def filepath_to_module(path: pathlib.Path, src_folder: pathlib.Path):
diff --git a/providers/google/tests/unit/google/cloud/links/test_alloy_db.py 
b/providers/google/tests/unit/google/cloud/links/test_alloy_db.py
deleted file mode 100644
index 41c7f22d86d..00000000000
--- a/providers/google/tests/unit/google/cloud/links/test_alloy_db.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-from __future__ import annotations
-
-from airflow.providers.google.cloud.links.alloy_db import (
-    AlloyDBBackupsLink,
-    AlloyDBClusterLink,
-    AlloyDBUsersLink,
-)
-
-TEST_LOCATION = "test-location"
-TEST_CLUSTER_ID = "test-cluster-id"
-TEST_PROJECT_ID = "test-project-id"
-EXPECTED_ALLOY_DB_CLUSTER_LINK_NAME = "AlloyDB Cluster"
-EXPECTED_ALLOY_DB_CLUSTER_LINK_KEY = "alloy_db_cluster"
-EXPECTED_ALLOY_DB_CLUSTER_LINK_FORMAT_STR = (
-    
"/alloydb/locations/{location_id}/clusters/{cluster_id}?project={project_id}"
-)
-EXPECTED_ALLOY_DB_USERS_LINK_NAME = "AlloyDB Users"
-EXPECTED_ALLOY_DB_USERS_LINK_KEY = "alloy_db_users"
-EXPECTED_ALLOY_DB_USERS_LINK_FORMAT_STR = (
-    
"/alloydb/locations/{location_id}/clusters/{cluster_id}/users?project={project_id}"
-)
-EXPECTED_ALLOY_DB_BACKUP_LINK_NAME = "AlloyDB Backups"
-EXPECTED_ALLOY_DB_BACKUP_LINK_KEY = "alloy_db_backups"
-EXPECTED_ALLOY_DB_BACKUP_LINK_FORMAT_STR = 
"/alloydb/backups?project={project_id}"
-
-
-class TestAlloyDBClusterLink:
-    def test_class_attributes(self):
-        assert AlloyDBClusterLink.key == EXPECTED_ALLOY_DB_CLUSTER_LINK_KEY
-        assert AlloyDBClusterLink.name == EXPECTED_ALLOY_DB_CLUSTER_LINK_NAME
-        assert AlloyDBClusterLink.format_str == 
EXPECTED_ALLOY_DB_CLUSTER_LINK_FORMAT_STR
-
-
-class TestAlloyDBUsersLink:
-    def test_class_attributes(self):
-        assert AlloyDBUsersLink.key == EXPECTED_ALLOY_DB_USERS_LINK_KEY
-        assert AlloyDBUsersLink.name == EXPECTED_ALLOY_DB_USERS_LINK_NAME
-        assert AlloyDBUsersLink.format_str == 
EXPECTED_ALLOY_DB_USERS_LINK_FORMAT_STR
-
-
-class TestAlloyDBBackupsLink:
-    def test_class_attributes(self):
-        assert AlloyDBBackupsLink.key == EXPECTED_ALLOY_DB_BACKUP_LINK_KEY
-        assert AlloyDBBackupsLink.name == EXPECTED_ALLOY_DB_BACKUP_LINK_NAME
-        assert AlloyDBBackupsLink.format_str == 
EXPECTED_ALLOY_DB_BACKUP_LINK_FORMAT_STR
diff --git 
a/providers/google/tests/unit/google/cloud/links/test_managed_kafka.py 
b/providers/google/tests/unit/google/cloud/links/test_managed_kafka.py
deleted file mode 100644
index 307be52adfa..00000000000
--- a/providers/google/tests/unit/google/cloud/links/test_managed_kafka.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-from __future__ import annotations
-
-from airflow.providers.google.cloud.links.managed_kafka import (
-    ApacheKafkaClusterLink,
-    ApacheKafkaClusterListLink,
-    ApacheKafkaConsumerGroupLink,
-    ApacheKafkaTopicLink,
-)
-
-TEST_LOCATION = "test-location"
-TEST_CLUSTER_ID = "test-cluster-id"
-TEST_PROJECT_ID = "test-project-id"
-TEST_TOPIC_ID = "test-topic-id"
-TEST_CONSUMER_GROUP_ID = "test-consumer-group-id"
-EXPECTED_MANAGED_KAFKA_CLUSTER_LINK_NAME = "Apache Kafka Cluster"
-EXPECTED_MANAGED_KAFKA_CLUSTER_LINK_KEY = "cluster_conf"
-EXPECTED_MANAGED_KAFKA_CLUSTER_LINK_FORMAT_STR = (
-    "/managedkafka/{location}/clusters/{cluster_id}?project={project_id}"
-)
-EXPECTED_MANAGED_KAFKA_CLUSTER_LIST_LINK_NAME = "Apache Kafka Cluster List"
-EXPECTED_MANAGED_KAFKA_CLUSTER_LIST_LINK_KEY = "cluster_list_conf"
-EXPECTED_MANAGED_KAFKA_CLUSTER_LIST_LINK_FORMAT_STR = 
"/managedkafka/clusters?project={project_id}"
-EXPECTED_MANAGED_KAFKA_TOPIC_LINK_NAME = "Apache Kafka Topic"
-EXPECTED_MANAGED_KAFKA_TOPIC_LINK_KEY = "topic_conf"
-EXPECTED_MANAGED_KAFKA_TOPIC_LINK_FORMAT_STR = (
-    
"/managedkafka/{location}/clusters/{cluster_id}/topics/{topic_id}?project={project_id}"
-)
-EXPECTED_MANAGED_KAFKA_CONSUMER_GROUP_LINK_NAME = "Apache Kafka Consumer Group"
-EXPECTED_MANAGED_KAFKA_CONSUMER_GROUP_LINK_KEY = "consumer_group_conf"
-EXPECTED_MANAGED_KAFKA_CONSUMER_GROUP_LINK_FORMAT_STR = (
-    
"/managedkafka/{location}/clusters/{cluster_id}/consumer_groups/{consumer_group_id}?project={project_id}"
-)
-
-
-class TestApacheKafkaClusterLink:
-    def test_class_attributes(self):
-        assert ApacheKafkaClusterLink.key == 
EXPECTED_MANAGED_KAFKA_CLUSTER_LINK_KEY
-        assert ApacheKafkaClusterLink.name == 
EXPECTED_MANAGED_KAFKA_CLUSTER_LINK_NAME
-        assert ApacheKafkaClusterLink.format_str == 
EXPECTED_MANAGED_KAFKA_CLUSTER_LINK_FORMAT_STR
-
-
-class TestApacheKafkaClusterListLink:
-    def test_class_attributes(self):
-        assert ApacheKafkaClusterListLink.key == 
EXPECTED_MANAGED_KAFKA_CLUSTER_LIST_LINK_KEY
-        assert ApacheKafkaClusterListLink.name == 
EXPECTED_MANAGED_KAFKA_CLUSTER_LIST_LINK_NAME
-        assert ApacheKafkaClusterListLink.format_str == 
EXPECTED_MANAGED_KAFKA_CLUSTER_LIST_LINK_FORMAT_STR
-
-
-class TestApacheKafkaTopicLink:
-    def test_class_attributes(self):
-        assert ApacheKafkaTopicLink.key == 
EXPECTED_MANAGED_KAFKA_TOPIC_LINK_KEY
-        assert ApacheKafkaTopicLink.name == 
EXPECTED_MANAGED_KAFKA_TOPIC_LINK_NAME
-        assert ApacheKafkaTopicLink.format_str == 
EXPECTED_MANAGED_KAFKA_TOPIC_LINK_FORMAT_STR
-
-
-class TestApacheKafkaConsumerGroupLink:
-    def test_class_attributes(self):
-        assert ApacheKafkaConsumerGroupLink.key == 
EXPECTED_MANAGED_KAFKA_CONSUMER_GROUP_LINK_KEY
-        assert ApacheKafkaConsumerGroupLink.name == 
EXPECTED_MANAGED_KAFKA_CONSUMER_GROUP_LINK_NAME
-        assert (
-            ApacheKafkaConsumerGroupLink.format_str == 
EXPECTED_MANAGED_KAFKA_CONSUMER_GROUP_LINK_FORMAT_STR
-        )

Reply via email to