From 82a71545197a873e7af43c8533eec42efdaf20b8 Mon Sep 17 00:00:00 2001 From: Eddy Zhang Date: Sat, 12 Sep 2026 00:50:38 +1000 Subject: [PATCH] Add unit tests for the Cloud Build links `providers/google/tests/unit/google/cloud/links/test_cloud_build.py` was listed in `OVERLOOKED_TESTS`, so `CloudBuildLink`, `CloudBuildListLink`, `CloudBuildTriggersListLink` and `CloudBuildTriggerDetailsLink` had no coverage. Adds class-attribute, `persist` and `_format_link` checks for each of them, following the shape of `test_bigquery.py` in the same directory. Drops the path from `OVERLOOKED_TESTS`. related: #35442 Generated-by: Claude Code --- .../unit/always/test_project_structure.py | 1 - .../google/cloud/links/test_cloud_build.py | 168 ++++++++++++++++++ 2 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 providers/google/tests/unit/google/cloud/links/test_cloud_build.py diff --git a/airflow-core/tests/unit/always/test_project_structure.py b/airflow-core/tests/unit/always/test_project_structure.py index 7ac2256b27f84..c52c388baf1da 100644 --- a/airflow-core/tests/unit/always/test_project_structure.py +++ b/airflow-core/tests/unit/always/test_project_structure.py @@ -127,7 +127,6 @@ def test_providers_modules_should_have_tests(self): "providers/fab/tests/unit/fab/www/test_views.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", diff --git a/providers/google/tests/unit/google/cloud/links/test_cloud_build.py b/providers/google/tests/unit/google/cloud/links/test_cloud_build.py new file mode 100644 index 0000000000000..9252af5a8567d --- /dev/null +++ b/providers/google/tests/unit/google/cloud/links/test_cloud_build.py @@ -0,0 +1,168 @@ +# +# 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. + +"""Tests for Cloud Build links.""" + +from __future__ import annotations + +from unittest import mock + +from airflow.providers.google.cloud.links.base import BASE_LINK +from airflow.providers.google.cloud.links.cloud_build import ( + BUILD_LINK, + BUILD_LIST_LINK, + BUILD_TRIGGER_DETAILS_LINK, + BUILD_TRIGGERS_LIST_LINK, + CloudBuildLink, + CloudBuildListLink, + CloudBuildTriggerDetailsLink, + CloudBuildTriggersListLink, +) + +TEST_BUILD_ID = "test-build-id" +TEST_PROJECT_ID = "test-project-id" +TEST_REGION = "test-region" +TEST_TRIGGER_ID = "test-trigger-id" + + +class TestCloudBuildLink: + def test_class_attributes(self): + assert CloudBuildLink.key == "cloud_build_key" + assert CloudBuildLink.name == "Cloud Build Details" + assert CloudBuildLink.format_str == BUILD_LINK + + def test_persist(self): + mock_context = mock.MagicMock() + mock_context["ti"] = mock.MagicMock() + mock_context["task"] = mock.MagicMock(spec=[]) + + CloudBuildLink.persist( + context=mock_context, + build_id=TEST_BUILD_ID, + project_id=TEST_PROJECT_ID, + region=TEST_REGION, + ) + + mock_context["ti"].xcom_push.assert_called_once_with( + key="cloud_build_key", + value={"build_id": TEST_BUILD_ID, "project_id": TEST_PROJECT_ID, "region": TEST_REGION}, + ) + + def test_format_link(self): + link = CloudBuildLink() + + result = link._format_link(build_id=TEST_BUILD_ID, project_id=TEST_PROJECT_ID, region=TEST_REGION) + + assert result == BASE_LINK + BUILD_LINK.format( + build_id=TEST_BUILD_ID, project_id=TEST_PROJECT_ID, region=TEST_REGION + ) + + +class TestCloudBuildListLink: + def test_class_attributes(self): + assert CloudBuildListLink.key == "cloud_build_list_key" + assert CloudBuildListLink.name == "Cloud Builds List" + assert CloudBuildListLink.format_str == BUILD_LIST_LINK + + def test_persist(self): + mock_context = mock.MagicMock() + mock_context["ti"] = mock.MagicMock() + mock_context["task"] = mock.MagicMock(spec=[]) + + CloudBuildListLink.persist( + context=mock_context, + project_id=TEST_PROJECT_ID, + region=TEST_REGION, + ) + + mock_context["ti"].xcom_push.assert_called_once_with( + key="cloud_build_list_key", + value={"project_id": TEST_PROJECT_ID, "region": TEST_REGION}, + ) + + def test_format_link(self): + link = CloudBuildListLink() + + result = link._format_link(project_id=TEST_PROJECT_ID, region=TEST_REGION) + + assert result == BASE_LINK + BUILD_LIST_LINK.format(project_id=TEST_PROJECT_ID, region=TEST_REGION) + + +class TestCloudBuildTriggersListLink: + def test_class_attributes(self): + assert CloudBuildTriggersListLink.key == "cloud_build_triggers_list_key" + assert CloudBuildTriggersListLink.name == "Cloud Build Triggers List" + assert CloudBuildTriggersListLink.format_str == BUILD_TRIGGERS_LIST_LINK + + def test_persist(self): + mock_context = mock.MagicMock() + mock_context["ti"] = mock.MagicMock() + mock_context["task"] = mock.MagicMock(spec=[]) + + CloudBuildTriggersListLink.persist( + context=mock_context, + project_id=TEST_PROJECT_ID, + region=TEST_REGION, + ) + + mock_context["ti"].xcom_push.assert_called_once_with( + key="cloud_build_triggers_list_key", + value={"project_id": TEST_PROJECT_ID, "region": TEST_REGION}, + ) + + def test_format_link(self): + link = CloudBuildTriggersListLink() + + result = link._format_link(project_id=TEST_PROJECT_ID, region=TEST_REGION) + + assert result == BASE_LINK + BUILD_TRIGGERS_LIST_LINK.format( + project_id=TEST_PROJECT_ID, region=TEST_REGION + ) + + +class TestCloudBuildTriggerDetailsLink: + def test_class_attributes(self): + assert CloudBuildTriggerDetailsLink.key == "cloud_build_triggers_details_key" + assert CloudBuildTriggerDetailsLink.name == "Cloud Build Triggers Details" + assert CloudBuildTriggerDetailsLink.format_str == BUILD_TRIGGER_DETAILS_LINK + + def test_persist(self): + mock_context = mock.MagicMock() + mock_context["ti"] = mock.MagicMock() + mock_context["task"] = mock.MagicMock(spec=[]) + + CloudBuildTriggerDetailsLink.persist( + context=mock_context, + project_id=TEST_PROJECT_ID, + region=TEST_REGION, + trigger_id=TEST_TRIGGER_ID, + ) + + mock_context["ti"].xcom_push.assert_called_once_with( + key="cloud_build_triggers_details_key", + value={"project_id": TEST_PROJECT_ID, "region": TEST_REGION, "trigger_id": TEST_TRIGGER_ID}, + ) + + def test_format_link(self): + link = CloudBuildTriggerDetailsLink() + + result = link._format_link(project_id=TEST_PROJECT_ID, region=TEST_REGION, trigger_id=TEST_TRIGGER_ID) + + assert result == BASE_LINK + BUILD_TRIGGER_DETAILS_LINK.format( + project_id=TEST_PROJECT_ID, region=TEST_REGION, trigger_id=TEST_TRIGGER_ID + )