@@ -246,45 +246,45 @@ void sessionCredentials() throws IOException {
246246 // Token caching tests
247247
248248 @ Test
249- void cacheWithValidTokenTest () throws IOException {
250- // Create mock HTTP client (shouldn't be called for valid token)
249+ void cacheWithValidRefreshableTokenTest () throws IOException {
250+ // Create mock HTTP client (shouldn't be called for valid token).
251251 HttpClient mockHttpClient = Mockito .mock (HttpClient .class );
252252
253- // Create a valid token with valid refresh token (expires in 1 hour - FRESH state)
253+ // Create a valid token with valid refresh token (expires in 1 hour - FRESH state).
254254 Instant futureTime = Instant .now ().plusSeconds (3600 );
255255 Token validToken = new Token ("valid_access_token" , "Bearer" , "valid_refresh_token" , futureTime );
256256
257- // Create mock token cache that returns the valid token
257+ // Create mock token cache that returns the valid token.
258258 TokenCache mockTokenCache = Mockito .mock (TokenCache .class );
259259 Mockito .doReturn (validToken ).when (mockTokenCache ).load ();
260260
261- // Create config with HTTP client and mock token cache
261+ // Create config with HTTP client and mock token cache.
262262 DatabricksConfig config =
263263 new DatabricksConfig ()
264264 .setAuthType ("external-browser" )
265265 .setHost ("https://test.databricks.com" )
266266 .setClientId ("test-client-id" )
267267 .setHttpClient (mockHttpClient );
268268
269- // We need to provide OIDC endpoints
269+ // We need to provide OIDC endpoints.
270270 OpenIDConnectEndpoints endpoints =
271271 new OpenIDConnectEndpoints (
272272 "https://test.databricks.com/oidc/v1/token" ,
273273 "https://test.databricks.com/oidc/v1/authorize" );
274274
275- // Create our provider with the mock token cache
275+ // Create our provider with the mock token cache.
276276 ExternalBrowserCredentialsProvider provider =
277277 Mockito .spy (new ExternalBrowserCredentialsProvider (mockTokenCache ));
278278
279- // Spy on the config to inject the endpoints
279+ // Spy on the config to inject the endpoints.
280280 DatabricksConfig spyConfig = Mockito .spy (config );
281281 Mockito .doReturn (endpoints ).when (spyConfig ).getOidcEndpoints ();
282282
283- // Configure provider
283+ // Configure provider.
284284 HeaderFactory headerFactory = provider .configure (spyConfig );
285285 assertNotNull (headerFactory , "HeaderFactory should be created" );
286286
287- // Verify headers contain the CACHED valid token (no refresh needed!)
287+ // Verify headers contain the CACHED valid token (no refresh needed!).
288288 Map <String , String > headers = headerFactory .headers ();
289289 assertEquals (
290290 "Bearer valid_access_token" ,
@@ -294,18 +294,78 @@ void cacheWithValidTokenTest() throws IOException {
294294 // Verify token was loaded from cache
295295 Mockito .verify (mockTokenCache , Mockito .times (1 )).load ();
296296
297- // Verify NO HTTP call was made (token is still valid, no refresh needed)
297+ // Verify NO HTTP call was made (token is still valid, no refresh needed).
298298 Mockito .verify (mockHttpClient , Mockito .never ()).execute (any (Request .class ));
299299
300- // Verify performBrowserAuth was NOT called since cached token is valid
300+ // Verify performBrowserAuth was NOT called since cached token is valid.
301301 Mockito .verify (provider , Mockito .never ())
302302 .performBrowserAuth (
303303 any (DatabricksConfig .class ),
304304 any (String .class ),
305305 any (String .class ),
306306 any (TokenCache .class ));
307307
308- // Verify token was NOT saved back to cache (we're using the cached one as-is)
308+ // Verify token was NOT saved back to cache (we're using the cached one as-is).
309+ Mockito .verify (mockTokenCache , Mockito .never ()).save (any (Token .class ));
310+ }
311+
312+ @ Test
313+ void cacheWithValidNonRefreshableTokenTest () throws IOException {
314+ // Create mock HTTP client (shouldn't be called for valid token).
315+ HttpClient mockHttpClient = Mockito .mock (HttpClient .class );
316+
317+ // Create a valid token WITHOUT refresh token (expires in 1 hour - FRESH state).
318+ Instant futureTime = Instant .now ().plusSeconds (3600 );
319+ Token validTokenNoRefresh = new Token ("valid_access_token" , "Bearer" , null , futureTime );
320+
321+ // Create mock token cache that returns the valid token.
322+ TokenCache mockTokenCache = Mockito .mock (TokenCache .class );
323+ Mockito .doReturn (validTokenNoRefresh ).when (mockTokenCache ).load ();
324+
325+ // Create config with HTTP client and mock token cache.
326+ DatabricksConfig config =
327+ new DatabricksConfig ()
328+ .setAuthType ("external-browser" )
329+ .setHost ("https://test.databricks.com" )
330+ .setClientId ("test-client-id" )
331+ .setHttpClient (mockHttpClient );
332+
333+ // We need to provide OIDC endpoints.
334+ OpenIDConnectEndpoints endpoints =
335+ new OpenIDConnectEndpoints (
336+ "https://test.databricks.com/oidc/v1/token" ,
337+ "https://test.databricks.com/oidc/v1/authorize" );
338+
339+ // Create our provider with the mock token cache.
340+ ExternalBrowserCredentialsProvider provider =
341+ Mockito .spy (new ExternalBrowserCredentialsProvider (mockTokenCache ));
342+
343+ // Spy on the config to inject the endpoints.
344+ DatabricksConfig spyConfig = Mockito .spy (config );
345+ Mockito .doReturn (endpoints ).when (spyConfig ).getOidcEndpoints ();
346+
347+ // Configure provider.
348+ HeaderFactory headerFactory = provider .configure (spyConfig );
349+ assertNotNull (headerFactory , "HeaderFactory should be created" );
350+
351+ // Verify headers contain the cached token (NOT browser auth!).
352+ Map <String , String > headers = headerFactory .headers ();
353+ assertEquals (
354+ "Bearer valid_access_token" ,
355+ headers .get ("Authorization" ),
356+ "Should use cached valid token even without refresh token" );
357+
358+ // Verify token was loaded from cache.
359+ Mockito .verify (mockTokenCache , Mockito .times (1 )).load ();
360+
361+ // Verify NO HTTP call was made (token is still valid, no refresh needed).
362+ Mockito .verify (mockHttpClient , Mockito .never ()).execute (any (Request .class ));
363+
364+ // Verify performBrowserAuth was NOT called.
365+ Mockito .verify (provider , Mockito .never ())
366+ .performBrowserAuth (any (DatabricksConfig .class ), any (), any (), any (TokenCache .class ));
367+
368+ // Verify no token was saved (we're using the cached one as-is).
309369 Mockito .verify (mockTokenCache , Mockito .never ()).save (any (Token .class ));
310370 }
311371
0 commit comments