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 bc09d7e5954 refactor: Fix _is_http_client_closed returning True for a 
transport that was never opened (#69329)
bc09d7e5954 is described below

commit bc09d7e5954dce3df668f9ae3fbaa0e0763930d8
Author: David Blain <[email protected]>
AuthorDate: Fri Jul 3 15:11:37 2026 +0200

    refactor: Fix _is_http_client_closed returning True for a transport that 
was never opened (#69329)
    
    When the Azure credential transport had never been opened 
(_has_been_opened=False,
    session=None), _is_http_client_closed incorrectly returned True, causing
    get_async_conn to evict and rebuild a perfectly valid cached request 
adapter on
    every call. A never-opened transport is not closed; return False.
---
 .../providers/microsoft/azure/hooks/msgraph.py     |  2 +-
 .../unit/microsoft/azure/hooks/test_msgraph.py     | 29 ++++++++++++++++++++++
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git 
a/providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/msgraph.py
 
b/providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/msgraph.py
index 4b7dcc31140..50ad3cb1e2f 100644
--- 
a/providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/msgraph.py
+++ 
b/providers/microsoft/azure/src/airflow/providers/microsoft/azure/hooks/msgraph.py
@@ -419,7 +419,7 @@ class KiotaRequestAdapterHook(BaseHook):
         transport = cast("AioHttpTransport", 
credential._client._pipeline._transport)
 
         if not transport._has_been_opened and transport.session is None:
-            return True
+            return False
         if transport.session is not None:
             return transport.session.closed
         return False
diff --git 
a/providers/microsoft/azure/tests/unit/microsoft/azure/hooks/test_msgraph.py 
b/providers/microsoft/azure/tests/unit/microsoft/azure/hooks/test_msgraph.py
index 6c1868f439c..ee9b0f87dfa 100644
--- a/providers/microsoft/azure/tests/unit/microsoft/azure/hooks/test_msgraph.py
+++ b/providers/microsoft/azure/tests/unit/microsoft/azure/hooks/test_msgraph.py
@@ -75,6 +75,21 @@ class TestKiotaRequestAdapterHook:
             assert isinstance(actual, HttpxRequestAdapter)
             assert actual.base_url == "https://graph.microsoft.com/v1.0/";
 
+    @classmethod
+    def mock_authentication_provider_never_opened(self) -> 
AuthenticationProvider:
+        """Return an auth provider whose transport has never been opened 
(session is None)."""
+        transport = Mock(spec=AioHttpTransport, _has_been_opened=False)
+        transport.session = None
+        pipeline = Mock(spec=AsyncPipelineClient)
+        pipeline._transport = transport
+        client = Mock(spec=AadClient)
+        client._pipeline = pipeline
+        credentials = Mock(spec=AsyncTokenCredential)
+        credentials._client = client
+        access_token_provider = Mock(spec=AzureIdentityAccessTokenProvider)
+        access_token_provider._credentials = credentials
+        return 
BaseBearerTokenAuthenticationProvider(access_token_provider=access_token_provider)
+
     @classmethod
     def mock_authentication_provider(self, closed: bool) -> 
AuthenticationProvider:
         transport = Mock(spec=AioHttpTransport, _has_been_opened=not closed)
@@ -593,6 +608,20 @@ class TestKiotaRequestAdapterHook:
             assert result is fresh_adapter
             assert hook.cached_request_adapters[hook.conn_id] == ("v1.0", 
fresh_adapter)
 
+    @pytest.mark.asyncio
+    async def 
test_get_async_conn_does_not_rebuild_adapter_when_transport_never_opened(self):
+        """get_async_conn must keep the cached adapter when transport has 
never been opened (session is None)."""
+        with patch_hook():
+            hook = KiotaRequestAdapterHook(conn_id="msgraph_api")
+            adapter = Mock(spec=HttpxRequestAdapter)
+            adapter._http_client = Mock(spec=AsyncClient, is_closed=False)
+            adapter._authentication_provider = 
self.mock_authentication_provider_never_opened()
+            hook.cached_request_adapters[hook.conn_id] = (hook.api_version, 
adapter)
+
+            result = await hook.get_async_conn()
+
+            assert result is adapter
+
     @pytest.mark.asyncio
     async def 
test_send_request_invalidates_cache_and_raises_on_any_error(self):
         """send_request evicts the cached adapter and re-raises on any request 
error."""

Reply via email to