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

shahar 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 436eb39c514 Pass credentials object to GCSFileSystem for automatic 
token refresh (#62013)
436eb39c514 is described below

commit 436eb39c514733a1f98a4d59261f0d7373a7e7f2
Author: Josef Šimánek <[email protected]>
AuthorDate: Mon Feb 16 15:06:04 2026 +0100

    Pass credentials object to GCSFileSystem for automatic token refresh 
(#62013)
---
 .../src/airflow/providers/google/cloud/fs/gcs.py   |  2 +-
 .../google/tests/unit/google/cloud/fs/__init__.py  | 16 +++++
 .../google/tests/unit/google/cloud/fs/test_gcs.py  | 82 ++++++++++++++++++++++
 3 files changed, 99 insertions(+), 1 deletion(-)

diff --git a/providers/google/src/airflow/providers/google/cloud/fs/gcs.py 
b/providers/google/src/airflow/providers/google/cloud/fs/gcs.py
index b10aa6ef9f5..ec1286f4ae9 100644
--- a/providers/google/src/airflow/providers/google/cloud/fs/gcs.py
+++ b/providers/google/src/airflow/providers/google/cloud/fs/gcs.py
@@ -51,7 +51,7 @@ def get_fs(conn_id: str | None, storage_options: dict[str, 
str] | None = None) -
     options = {
         "project": g.project_id,
         "access": g.extras.get(GCS_ACCESS, "full_control"),
-        "token": g._get_access_token(),
+        "token": g.get_credentials(),
         "consistency": g.extras.get(GCS_CONSISTENCY, "none"),
         "cache_timeout": g.extras.get(GCS_CACHE_TIMEOUT),
         "requester_pays": g.extras.get(GCS_REQUESTER_PAYS, False),
diff --git a/providers/google/tests/unit/google/cloud/fs/__init__.py 
b/providers/google/tests/unit/google/cloud/fs/__init__.py
new file mode 100644
index 00000000000..13a83393a91
--- /dev/null
+++ b/providers/google/tests/unit/google/cloud/fs/__init__.py
@@ -0,0 +1,16 @@
+# 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.
diff --git a/providers/google/tests/unit/google/cloud/fs/test_gcs.py 
b/providers/google/tests/unit/google/cloud/fs/test_gcs.py
new file mode 100644
index 00000000000..70e6f0fc321
--- /dev/null
+++ b/providers/google/tests/unit/google/cloud/fs/test_gcs.py
@@ -0,0 +1,82 @@
+# 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 unittest.mock import MagicMock, patch
+
+import pytest
+
+pytest.importorskip("gcsfs")
+
+TEST_CONN = "google_cloud_test_conn"
+
+
[email protected](scope="module", autouse=True)
+def _setup_connections():
+    with pytest.MonkeyPatch.context() as mp_ctx:
+        mp_ctx.setenv(f"AIRFLOW_CONN_{TEST_CONN}".upper(), 
"google-cloud-platform://")
+        yield
+
+
+class TestGCSFilesystem:
+    @patch("airflow.providers.google.cloud.fs.gcs.GoogleBaseHook")
+    @patch("gcsfs.GCSFileSystem")
+    def test_get_fs_passes_credentials_object(self, mock_gcsfs, mock_hook):
+        """Test that get_fs passes a Credentials object to GCSFileSystem."""
+        from airflow.providers.google.cloud.fs.gcs import get_fs
+
+        mock_credentials = MagicMock()
+        mock_hook_instance = MagicMock()
+        mock_hook_instance.get_credentials.return_value = mock_credentials
+        mock_hook_instance.project_id = "test-project"
+        mock_hook_instance.extras = {}
+        mock_hook.return_value = mock_hook_instance
+
+        get_fs(conn_id=TEST_CONN)
+
+        mock_hook_instance.get_credentials.assert_called_once()
+        call_kwargs = mock_gcsfs.call_args.kwargs
+        assert call_kwargs["token"] is mock_credentials
+
+    @patch("gcsfs.GCSFileSystem")
+    def test_get_fs_no_conn_id(self, mock_gcsfs):
+        """Test that get_fs works without conn_id."""
+        from airflow.providers.google.cloud.fs.gcs import get_fs
+
+        get_fs(conn_id=None)
+
+        mock_gcsfs.assert_called_once_with()
+
+    @patch("airflow.providers.google.cloud.fs.gcs.GoogleBaseHook")
+    @patch("gcsfs.GCSFileSystem")
+    def test_get_fs_with_anonymous_credentials(self, mock_gcsfs, mock_hook):
+        """Test that get_fs works with anonymous credentials."""
+        from google.auth.credentials import AnonymousCredentials
+
+        from airflow.providers.google.cloud.fs.gcs import get_fs
+
+        anonymous_creds = AnonymousCredentials()
+        mock_hook_instance = MagicMock()
+        mock_hook_instance.get_credentials.return_value = anonymous_creds
+        mock_hook_instance.project_id = None
+        mock_hook_instance.extras = {}
+        mock_hook.return_value = mock_hook_instance
+
+        get_fs(conn_id=TEST_CONN)
+
+        call_kwargs = mock_gcsfs.call_args.kwargs
+        assert isinstance(call_kwargs["token"], AnonymousCredentials)

Reply via email to