@@ -124,51 +124,103 @@ def connection_manager(self):
124124 DatabricksConnectionManager ._dbr_capabilities_cache = {}
125125 return mgr
126126
127- @patch .object (DatabricksConnectionManager , "_cache_dbr_capabilities " )
127+ @patch .object (DatabricksConnectionManager , "_try_cache_dbr_capabilities " )
128128 def test_fresh_connection_caches_capabilities_before_setting_them (
129- self , mock_cache_dbr , connection_manager
129+ self , mock_try_cache , connection_manager
130130 ):
131- """_create_fresh_connection must call _cache_dbr_capabilities before reading the cache."""
131+ """_create_fresh_connection must call _try_cache_dbr_capabilities before reading the
132+ cache."""
132133 expected_caps = DBRCapabilities (dbr_version = (15 , 4 ), is_sql_warehouse = False )
133134
134135 def populate_cache (creds , http_path ):
135136 DatabricksConnectionManager ._dbr_capabilities_cache [http_path ] = expected_caps
136137
137- mock_cache_dbr .side_effect = populate_cache
138+ mock_try_cache .side_effect = populate_cache
138139
139140 ctx = QueryContextWrapper (compute_name = "alternate_compute" )
140141 conn = connection_manager ._create_fresh_connection ("test_model" , ctx )
141142
142- mock_cache_dbr .assert_called_once_with (
143+ mock_try_cache .assert_called_once_with (
143144 connection_manager .profile .credentials , self .NAMED_COMPUTE_HTTP_PATH
144145 )
145146 assert conn .capabilities == expected_caps
146147 assert conn .capabilities .has_capability (DBRCapability .ICEBERG )
147148
148- @patch .object (DatabricksConnectionManager , "_cache_dbr_capabilities " )
149- def test_fresh_connection_without_eager_cache_gets_empty_defaults (
150- self , mock_cache_dbr , connection_manager
149+ @patch .object (DatabricksConnectionManager , "_try_cache_dbr_capabilities " )
150+ def test_fresh_connection_falls_back_to_empty_defaults_when_eager_cache_is_noop (
151+ self , mock_try_cache , connection_manager
151152 ):
152- """Without the eager cache call, named compute gets empty (broken) capabilities.
153-
154- This test documents the pre-fix behavior: if _cache_dbr_capabilities is a no-op,
155- the connection falls back to DBRCapabilities() which has all capabilities disabled.
156- """
153+ """When the eager try-cache is a no-op (e.g. version query not yet possible), the
154+ connection gets default capabilities. open() will populate the cache correctly later."""
157155 ctx = QueryContextWrapper (compute_name = "alternate_compute" )
158156 conn = connection_manager ._create_fresh_connection ("test_model" , ctx )
159157
160158 assert conn .capabilities .dbr_version is None
161159 assert not conn .capabilities .is_sql_warehouse
162160 assert not conn .capabilities .has_capability (DBRCapability .ICEBERG )
163161
164- @patch .object (DatabricksConnectionManager , "_cache_dbr_capabilities " )
165- def test_default_compute_cache_is_idempotent (self , mock_cache_dbr , connection_manager ):
162+ @patch .object (DatabricksConnectionManager , "_try_cache_dbr_capabilities " )
163+ def test_default_compute_cache_is_idempotent (self , mock_try_cache , connection_manager ):
166164 """For default compute with a warm cache, the eager call is a no-op."""
167165 warm_caps = DBRCapabilities (dbr_version = (15 , 4 ), is_sql_warehouse = False )
168166 DatabricksConnectionManager ._dbr_capabilities_cache [self .DEFAULT_HTTP_PATH ] = warm_caps
169167
170168 ctx = QueryContextWrapper ()
171169 conn = connection_manager ._create_fresh_connection ("test_model" , ctx )
172170
173- mock_cache_dbr .assert_called_once ()
171+ mock_try_cache .assert_called_once ()
174172 assert conn .capabilities == warm_caps
173+
174+
175+ class TestTryCacheDbr :
176+ """Unit tests for _try_cache_dbr_capabilities."""
177+
178+ HTTP_PATH = "sql/protocolv1/o/1234567890123456/cluster-abc"
179+
180+ @pytest .fixture (autouse = True )
181+ def clear_cache (self ):
182+ DatabricksConnectionManager ._dbr_capabilities_cache = {}
183+ yield
184+ DatabricksConnectionManager ._dbr_capabilities_cache = {}
185+
186+ @patch .object (DatabricksConnectionManager , "_query_dbr_version" , return_value = None )
187+ def test_does_not_write_to_cache_when_version_is_none (self , mock_query ):
188+ """When the version query returns None, the cache must not be written.
189+
190+ This prevents a poisoned None entry from blocking the authoritative write in open().
191+ """
192+ creds = Mock (spec = DatabricksCredentials )
193+ creds .cluster_id = None
194+
195+ DatabricksConnectionManager ._try_cache_dbr_capabilities (creds , self .HTTP_PATH )
196+
197+ assert self .HTTP_PATH not in DatabricksConnectionManager ._dbr_capabilities_cache
198+ mock_query .assert_called_once_with (creds , self .HTTP_PATH )
199+
200+ @patch .object (DatabricksConnectionManager , "_query_dbr_version" , return_value = (15 , 4 ))
201+ def test_writes_to_cache_when_version_is_known (self , mock_query ):
202+ """When the version query succeeds, capabilities are cached correctly."""
203+ creds = Mock (spec = DatabricksCredentials )
204+ creds .cluster_id = None
205+
206+ DatabricksConnectionManager ._try_cache_dbr_capabilities (creds , self .HTTP_PATH )
207+
208+ mock_query .assert_called_once_with (creds , self .HTTP_PATH )
209+ caps = DatabricksConnectionManager ._dbr_capabilities_cache .get (self .HTTP_PATH )
210+ assert caps is not None
211+ assert caps .dbr_version == (15 , 4 )
212+ assert not caps .is_sql_warehouse
213+ assert caps .has_capability (DBRCapability .ICEBERG )
214+
215+ @patch .object (DatabricksConnectionManager , "_query_dbr_version" , return_value = (15 , 4 ))
216+ def test_skips_write_when_already_cached (self , mock_query ):
217+ """If the path is already in cache, the version query is never made."""
218+ creds = Mock (spec = DatabricksCredentials )
219+ creds .cluster_id = None
220+ existing = DBRCapabilities (dbr_version = (14 , 3 ), is_sql_warehouse = False )
221+ DatabricksConnectionManager ._dbr_capabilities_cache [self .HTTP_PATH ] = existing
222+
223+ DatabricksConnectionManager ._try_cache_dbr_capabilities (creds , self .HTTP_PATH )
224+
225+ mock_query .assert_not_called ()
226+ assert DatabricksConnectionManager ._dbr_capabilities_cache [self .HTTP_PATH ] is existing
0 commit comments